home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir40 / pm_10_94.zip / PMODE.ASM < prev    next >
Assembly Source File  |  1994-10-12  |  140KB  |  3,198 lines

  1. ; PMODE v3.04 DPMI/VCPI/XMS/raw protected mode interface kernel.
  2. ; Copyright (c) 1994, Tran (a.k.a. Thomas Pytel).
  3.  
  4. public  _pm_selectors, _pm_pagetables, _pm_rmstacklen, _pm_rmstacks
  5. public  _pm_callbacks, _pm_pmstacklen, _pm_pmstacks
  6. public  _pm_info, _pm_init
  7.  
  8. public  pmstackbase, pmstacktop, rmstackbase, rmstacktop
  9.  
  10. .386p
  11. locals
  12. PMODE_TEXT      segment para public use16 'CODE'
  13. assume  cs:PMODE_TEXT, ds:PMODE_TEXT
  14.  
  15. off             equ     offset
  16.  
  17. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  18. ; DATA
  19. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  20. SELCODE         = 08h                   ; PMODE_TEXT code selector
  21. SELZERO         = 10h                   ; selector of entire memory space
  22. SELCALLBACKDS   = 18h                   ; callback DS selector
  23. SELREAL         = 20h                   ; real mode attributes selector
  24. SELVCPITSS      = 28h                   ; TSS selector for VCPI
  25. SELVCPICODE     = 30h                   ; VCPI call code selector
  26. SYSSELECTORS    = 9                     ; number of system selectors in GDT
  27.  
  28. align 4
  29. dpmiepmode      dd      ?               ; DPMI enter pmode addx
  30. codebase        dd      ?               ; PMODE_TEXT linear address
  31. vcpistrucaddx   dd      off vcpi_cr3    ; VCPI switch structure linear address
  32. vcpiswitchstack dd      ?               ; VCPI temporary mode switch stack
  33. oldint15vector  dd      ?               ; preserved INT 15h vector
  34.  
  35. pmstacklen      dd      ?               ; protected mode stack length in bytes
  36. pmstackbase    dd    ?        ; bottom of protected mode stack area
  37. pmstacktop      dd      ?               ; top of protected mode stack area
  38. callbackbase    dd      ?               ; base of real mode callbacks
  39. callbackseg     dw      ?               ; segment of callbacks
  40.  
  41. selzero         dw      SELZERO         ; for immediate segreg loading
  42. selcallbackds   dw      SELCALLBACKDS   ; for immediate segreg loading
  43.  
  44. rawextmemused   dw      1               ; raw extended memory used in K
  45. rawextmembase   dd      0ffffffffh      ; raw extended memory base
  46. rawextmemtop    dd      0               ; raw extended memory top
  47.  
  48. rmstackbase     dw      ?               ; bottom of real mode stack area
  49. rmstacktop      dw      ?               ; top of real mode stack area
  50. rmstackparmtop  dw      ?               ; for functions 0300h, 0301h, 0302h
  51.  
  52. gdtseg          dw      ?               ; segment of GDT
  53.  
  54. gdtlimit        dw      ?               ; GDT limit                          |
  55. gdtbase         dd      ?               ; GDT base                           |
  56. idtlimit        dw      7ffh            ; IDT limit                         |
  57. idtbase         dd      ?               ; IDT base                          |
  58. rmidtlimit      dw      3ffh            ; real mode IDT limit                |
  59. rmidtbase       dd      0               ; real mode IDT base                 |
  60.  
  61. rmtopmswrout    dw      off v_rmtopmsw  ; addx of real to protected routine
  62. pmtormswrout    dd      off v_pmtormsw  ; addx of protected to real routine
  63.  
  64. pagetablebase   dd      ?               ; base of page table area
  65. pagetabletop    dd      ?               ; top of page table area
  66. pagetablenum    db      ?               ; number of page tables
  67.  
  68. _pm_pagetables  db      1               ; number of page tables under VCPI
  69. _pm_selectors   dw      64              ; max selectors under VCPI/XMS/raw
  70. _pm_rmstacklen  dw      40h             ; real mode stack length, in para
  71. _pm_pmstacklen  dw      80h             ; protected mode stack length, in para
  72. _pm_rmstacks    db      4               ; real mode stack nesting
  73. _pm_pmstacks    db      2               ; protected mode stack nesting
  74. _pm_callbacks   db      16              ; number of real mode callbacks
  75.                 db      ?               ; for alignment
  76.  
  77. processortype   db      ?               ; processor type                     |
  78. pmodetype       db      2               ; protected mode type                |
  79. picslave        db      70h             ; PIC slave base interrupt          |
  80. picmaster       db      8               ; PIC master base interrupt         |
  81.  
  82. tempd0          label   dword           ; temporary variables                |
  83. tempw0          label   word            ;                                    |
  84. tempb0          db      ?               ;                                    |
  85. tempb1          db      ?               ;                                    |
  86. tempw1          label   word            ;                                    |
  87. tempb2          db      ?               ;                                    |
  88. tempb3          db      ?               ;                                    |
  89. tempd1          label   dword           ;                                    |
  90. tempw2          label   word            ;                                    |
  91. tempb4          db      ?               ;                                    |
  92. tempb5          db      ?               ;                                    |
  93. tempw3          label   word            ;                                    |
  94. tempb6          db      ?               ;                                    |
  95. tempb7          db      ?               ;                                    |
  96.  
  97. xms_callip      dw      ?               ; XMS driver offset                 |
  98. xms_callcs      dw      ?               ; XMS driver segment                |
  99.  
  100. vcpi_cr3        dd      ?               ; VCPI CR3 value for protected mode  |
  101. vcpi_gdtaddx    dd      off gdtlimit    ; linear addx of GDT limit and base  |
  102. vcpi_idtaddx    dd      off idtlimit    ; linear addx of IDT limit and base  |
  103. vcpi_selldt     dw      0               ; LDT selector for protected mode    |
  104. vcpi_seltss     dw      SELVCPITSS      ; TSS selector for protected mode    |
  105. vcpi_eip        dd      off v_rmtopmswpm; destination EIP in protected mode  |
  106. vcpi_cs         dw      SELCODE         ; destination CS in protected mode   |
  107.  
  108. vcpi_calleip    dd      ?               ; VCPI protected mode call offset   |
  109. vcpi_callcs     dw      SELVCPICODE     ; VCPI protected mode call selector |
  110.  
  111. initrouttbl     dw      r_init, x_init, v_init, d_init
  112.  
  113. int31functbl    dw      0900h, 0901h, 0902h, 0000h, 0001h, 0003h, 0006h, 0007h
  114.                 dw      0008h, 0009h, 0200h, 0201h, 0204h, 0205h, 0305h, 0306h
  115.                 dw      0400h
  116.                 dw      000ah, 000bh, 000ch, 000eh, 000fh
  117.                 dw      0300h, 0301h, 0302h
  118.                 dw      0303h, 0304h
  119.                 dw      0500h, 0501h, 0502h, 0503h, 050ah
  120. INT31FUNCNUM    = ($ - int31functbl) / 2
  121.  
  122. int31routtbl    dw      int310900, int310901, int310902, int310000
  123.                 dw      int310001, int310003, int310006, int310007
  124.                 dw      int310008, int310009, int310200, int310201
  125.                 dw      int310204, int310205, int310305, int310306
  126.                 dw      int310400
  127.                 dw      int31000a, int31000b, int31000c, int31000e, int31000f
  128.                 dw      int310300, int310301, int310302
  129.                 dw      int310303, int310304
  130. int31mrouttbl   dw      int310500v, int310501v, int310502v, int310503v
  131.                 dw      int31050av
  132. int31mxrouttbl  dw      int310500x, int310501x, int310502x, int310503x
  133.                 dw      int31050ax
  134. int31mrrouttbl  dw      int310500r, int310501r, int310502r, int310503r
  135.                 dw      int31050ar
  136. int31mnrouttbl  dw      int310500rnomem, int31fail8013, int31fail8023
  137.                 dw      int31fail8023, int31fail8023
  138.  
  139. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  140. ; DETECT/INIT CODE
  141. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  142.  
  143. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  144. ; Get protected mode info
  145. ; Out:
  146. ;   AX = return code:
  147. ;     0000h = successful
  148. ;     0001h = no 80386+ detected
  149. ;     0002h = system already in protected mode and no VCPI or DPMI found
  150. ;     0003h = DPMI - host is not 32bit
  151. ;   CF = set on error, if no error:
  152. ;     BX = number of paragraphs needed for protected mode data (may be 0)
  153. ;     CL = processor type:
  154. ;       03h = 80386
  155. ;       04h = 80486
  156. ;       05h = 80586
  157. ;       06h-FFh = reserved for future use
  158. ;     CH = protected mode type:
  159. ;       00h = raw
  160. ;       01h = XMS
  161. ;       02h = VCPI
  162. ;       03h = DPMI
  163. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  164. _pm_info:
  165.         push dx si di ds es bx cx       ; preserve registers
  166.  
  167.         push cs                         ; DS = CS (PMODE_TEXT)
  168.         pop ds
  169.  
  170.         mov ax,1687h                    ; check for DPMI
  171.         int 2fh
  172.  
  173.         or ax,ax                        ; DPMI present?
  174.         jnz short @@infof0              ; if no, go on
  175.  
  176.         mov ax,3                        ; error code in case DPMI not 32bit
  177.         test bl,1                       ; is DPMI 32bit?
  178.         jz @@infofail                   ; if no, fail
  179.  
  180.         mov ax,1                        ; error code in case no processor 386+
  181.         cmp cl,3                        ; is processor 386+?
  182.         jb @@infofail                   ; if no, fail
  183.  
  184.         mov word ptr dpmiepmode[0],di   ; store DPMI initial mode switch addx
  185.         mov word ptr dpmiepmode[2],es
  186.  
  187.         mov bx,si                       ; BX = number of paragraphs needed
  188.         mov ch,3                        ; pmode type is 3 (DPMI)
  189.  
  190.         jmp @@infook                    ; go to done ok
  191.  
  192. ;-----------------------------------------------------------------------------
  193. @@infof0:
  194.         call detect_processor           ; get processor type
  195.  
  196.         mov ax,1                        ; error code in case no processor 386+
  197.         cmp cl,3                        ; is processor 386+?
  198.         jb @@infofail                   ; if no, fail
  199.  
  200.         mov processortype,cl            ; store processor type
  201.  
  202. ;-----------------------------------------------------------------------------
  203.         xor ax,ax                       ; get INT 67h vector
  204.         mov es,ax
  205.         mov ax,es:[67h*4]
  206.         or ax,es:[67h*4+2]              ; is vector NULL
  207.         jz short @@infof2               ; if yes, no VCPI
  208.  
  209.         mov ax,0de00h                   ; call VCPI installation check
  210.         int 67h
  211.         or ah,ah                        ; AH returned as 0?
  212.         jnz short @@infof2              ; if no, no VCPI
  213.  
  214.         movzx bx,_pm_pagetables         ; BX = VCPI page table memory needed
  215.         shl bx,8                        ; 100h paragraphs per page table
  216.         add bx,100h+0ffh+7+80h          ; + page dir + align buf + TSS + IDT
  217.  
  218.         mov ch,2                        ; pmode type is 2 (VCPI)
  219.  
  220.         jmp short @@infof1              ; go to figure other memory needed
  221.  
  222. ;-----------------------------------------------------------------------------
  223. @@infof2:
  224.         smsw ax                         ; AX = machine status word
  225.         test al,1                       ; is system in protected mode?
  226.         mov ax,2                        ; error code in case protected mode
  227.         jnz short @@infofail            ; if in protected mode, fail
  228.  
  229.         mov ax,4300h                    ; chek for XMS
  230.         int 2fh
  231.         cmp al,80h                      ; XMS present?
  232.         sete ch                         ; if yes, pmode type is XMS
  233.  
  234.         mov bx,80h                      ; BX = memory requirement (IDT)
  235.  
  236. ;-----------------------------------------------------------------------------
  237. @@infof1:
  238.         movzx ax,_pm_rmstacks           ; size of real mode stack area
  239.         imul ax,_pm_rmstacklen
  240.         add bx,ax
  241.  
  242.         movzx ax,_pm_pmstacks           ; size of protected mode stack area
  243.         imul ax,_pm_pmstacklen
  244.         add bx,ax
  245.  
  246.         movzx ax,_pm_callbacks          ; size of callbacks
  247.         imul ax,25
  248.         add ax,0fh
  249.         shr ax,4
  250.         add bx,ax
  251.  
  252.         mov ax,_pm_selectors            ; size of GDT
  253.         add ax,1+SYSSELECTORS+5
  254.         shr ax,1
  255.         add bx,ax
  256.  
  257.         jmp short @@infook              ; go to done ok
  258.  
  259. ;-----------------------------------------------------------------------------
  260. @@infofail:
  261.         pop cx bx                       ; restore BX and CX
  262.         stc                             ; carry set, failed
  263.         jmp short @@infodone
  264.  
  265. ;-----------------------------------------------------------------------------
  266. @@infook:
  267.         mov pmodetype,ch                ; store pmode type
  268.  
  269.         add sp,4                        ; skip BX and CX on stack
  270.         xor ax,ax                       ; success code, also clear carry flag
  271.  
  272. ;-----------------------------------------------------------------------------
  273. @@infodone:
  274.         pop es ds di si dx              ; restore other registers
  275.         retf                            ; return
  276.  
  277. ;─────────────────────────────────────────────────────────────────────────────
  278. detect_processor:                       ; get processor: 386, 486, or 586
  279.         xor cl,cl                       ; processor type 0 in case of exit
  280.  
  281.         pushf                           ; transfer FLAGS to BX
  282.         pop bx
  283.  
  284.         mov ax,bx                       ; try to clear high 4 bits of FLAGS
  285.         and ah,0fh
  286.  
  287.         push ax                         ; transfer AX to FLAGS
  288.         popf
  289.         pushf                           ; transfer FLAGS back to AX
  290.         pop ax
  291.  
  292.         and ah,0f0h                     ; isolate high 4 bits
  293.         cmp ah,0f0h
  294.         je short @@detect_processordone ; if bits are set, CPU is 8086/8
  295.  
  296.         mov cl,2                        ; processor type 2 in case of exit
  297.  
  298.         or bh,0f0h                      ; try to set high 4 bits of FLAGS
  299.  
  300.         push bx                         ; transfer BX to FLAGS
  301.         popf
  302.         pushf                           ; transfer FLAGS to AX
  303.         pop ax
  304.  
  305.         and ah,0f0h                     ; isolate high 4 bits
  306.         jz short @@detect_processordone ; if bits are not set, CPU is 80286
  307.  
  308.         inc cx                          ; processor type 3 in case of exit
  309.  
  310.         push eax ebx                    ; preserve 32bit registers
  311.  
  312.         pushfd                          ; transfer EFLAGS to EBX
  313.         pop ebx
  314.  
  315.         mov eax,ebx                     ; try to flip AC bit in EFLAGS
  316.         xor eax,40000h
  317.  
  318.         push eax                        ; transfer EAX to EFLAGS
  319.         popfd
  320.         pushfd                          ; transfer EFLAGS back to EAX
  321.         pop eax
  322.  
  323.         xor eax,ebx                     ; AC bit fliped?
  324.         jz short @@detect_processordone2; if no, CPU is 386
  325.  
  326.         inc cx                          ; processor type 4 in case of exit
  327.  
  328.         mov eax,ebx                     ; try to flip ID bit in EFLAGS
  329.         xor eax,200000h
  330.  
  331.         push eax                        ; transfer EAX to EFLAGS
  332.         popfd
  333.         pushfd                          ; transfer EFLAGS back to EAX
  334.         pop eax
  335.  
  336.         xor eax,ebx                     ; ID bit fliped?
  337.         jz short @@detect_processordone2; if no, CPU is 486
  338.  
  339.         inc cx                          ; processor type 5, CPU is 586
  340.  
  341. @@detect_processordone2:
  342.         pop ebx eax                     ; restore 32bit registers
  343.  
  344. @@detect_processordone:
  345.         ret                             ; return
  346.  
  347. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  348. ; Initialize protected mode
  349. ; In:
  350. ;   ES = real mode segment for protected mode data (ignored if not needed)
  351. ; Out:
  352. ;   AX = return code:
  353. ;     0000h = successful
  354. ;     0001h = no 80386+ detected
  355. ;     0002h = system already in protected mode and no VCPI or DPMI found
  356. ;     0003h = DPMI - host is not 32bit
  357. ;     0004h = could not enable A20 gate
  358. ;     0005h = DPMI - could not enter 32bit protected mode
  359. ;     0006h = DPMI - could not allocate needed selectors
  360. ;   CF = set on error, if no error:
  361. ;     ESP = high word clear
  362. ;     CS = 16bit selector for real mode CS with limit of 64k
  363. ;     SS = selector for real mode SS with limit of 64k
  364. ;     DS = selector for real mode DS with limit of 64k
  365. ;     ES = selector for PSP with limit of 100h
  366. ;     FS = 0 (NULL selector)
  367. ;     GS = 0 (NULL selector)
  368. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  369. _pm_init:
  370.         push bx cx                      ; get initial info on protected mode
  371.         call far ptr _pm_info
  372.         pop cx bx
  373.         jnc short @@initf0              ; error?
  374.  
  375.         retf                            ; yup, abort
  376.  
  377. @@initf0:                               ; no error, init protected mode
  378.         pushad
  379.         push ds
  380.         mov bp,sp
  381.         push cs                         ; DS = PMODE_TEXT
  382.         pop ds
  383.         cld
  384.  
  385.         mov eax,PMODE_TEXT              ; set base addx of PMODE_TEXT
  386.         shl eax,4
  387.         mov codebase,eax
  388.  
  389.         movzx bx,pmodetype              ; jump to appropriate init code
  390.         shl bx,1
  391.         jmp initrouttbl[bx]
  392.  
  393. ;═════════════════════════════════════════════════════════════════════════════
  394. d_init:                                 ; DPMI protected mode init
  395.         pop ds                          ; get original caller DS from stack
  396.         mov ax,1                        ; enter DPMI protected mode
  397.         call cs:dpmiepmode
  398.         push ds                         ; put DS back onto stack
  399.         jnc short dvxr_init             ; error? if not, go on with init
  400.  
  401.         mov bx,6                        ; error entering protected mode, set
  402.         cmp ax,8011h                    ;  error code and abort
  403.         stc
  404.         je short init_done
  405.         mov bl,5                        ; error code 5, not 6
  406.  
  407. ;-----------------------------------------------------------------------------
  408. init_done:                              ; return with return code
  409.         mov [bp+30],bx
  410.         pop ds
  411.         popad
  412.         retf
  413.  
  414. ;─────────────────────────────────────────────────────────────────────────────
  415. dvxr_init:                              ; DPMI/VCPI/XMS/raw common init tail
  416.         mov bx,cs                       ; BX = CS if needed for same seg exit
  417.         cmp word ptr [bp+36],PMODE_TEXT ; call came from same segment?
  418.         je short @@dvxr_initdone        ; if yes, done now
  419.  
  420.         xor ax,ax                       ; allocate selector for return code
  421.         mov cx,1
  422.         int 31h
  423.         jnc short @@dvxr_initf0
  424.  
  425.         mov ah,4ch                      ; could not allocate selector
  426.         int 21h                         ; terminate immediately
  427.  
  428. @@dvxr_initf0:
  429.         mov bx,ax                       ; new code descriptor for return
  430.  
  431.         mov ax,0007h                    ; set base address of calling segment
  432.         xor cx,cx
  433.         mov dx,[bp+36]
  434.         shld cx,dx,4
  435.         shl dx,4
  436.         int 31h
  437.  
  438.         mov ax,0008h                    ; set selector limit of 64k
  439.         xor cx,cx
  440.         mov dx,0ffffh
  441.         int 31h
  442.  
  443.         mov ax,0009h                    ; set selector type and access rights
  444.         mov dx,cs                       ; get DPL from current CPL, and access
  445.         lar cx,dx                       ;  rights and type from current CS
  446.         shr cx,8                        ; type is already 16bit code segment
  447.         int 31h
  448.  
  449. @@dvxr_initdone:
  450.         mov [bp+36],bx                  ; store selector in return address
  451.         xor bx,bx                       ; init successful, carry clear
  452.         jmp init_done
  453.  
  454. ;═════════════════════════════════════════════════════════════════════════════
  455. v_init:                                 ; VCPI protected mode init
  456.         mov ax,0de0ah                   ; get PIC mappings
  457.         int 67h
  458.         mov picmaster,bl
  459.         mov picslave,cl
  460.  
  461.         mov eax,codebase                ; adjust addresses for VCPI structure
  462.         add vcpi_gdtaddx,eax
  463.         add vcpi_idtaddx,eax
  464.         add vcpistrucaddx,eax
  465.  
  466.         mov dx,es                       ; align data area on page
  467.         add dx,0ffh
  468.         xor dl,dl
  469.         mov es,dx
  470.  
  471.         movzx eax,dx                    ; set base and top of page table area
  472.         shl eax,4
  473.         add eax,1000h
  474.         mov pagetablebase,eax
  475.         movzx ecx,_pm_pagetables
  476.         shl ecx,12
  477.         add eax,ecx
  478.         mov pagetabletop,eax
  479.  
  480.         xor di,di                       ; clear page dir and first page table
  481.         mov cx,1000h
  482.         xor ax,ax
  483.         rep stosw
  484.  
  485.         mov gs,dx                       ; FS = segment of page directory
  486.         lea eax,[edx+100h]
  487.         mov es,ax                       ; ES = segment of first page table
  488.         mov fs,ax                       ; GS = segment of first page table
  489.  
  490.         push ss                         ; stack space for VCPI descriptors
  491.         pop ds
  492.         sub sp,8*3
  493.         mov si,sp
  494.  
  495.         xor di,di                       ; get VCPI protected mode interface
  496.         mov ax,0de01h
  497.         int 67h
  498.  
  499.         push cs                         ; DS = PMODE_TEXT
  500.         pop ds
  501.  
  502.         mov vcpi_calleip,ebx            ; store protected mode VCPI call EIP
  503.         movzx si,dh                     ; get physical address of page dir
  504.         shl si,2                        ;  from first page table for CR3
  505.         lods dword ptr fs:[si]
  506.         mov vcpi_cr3,eax
  507.  
  508. @@v_initl0:
  509.         and byte ptr es:[di+1],0f1h     ; clear bits 9-11 in copied page table
  510.         sub di,4
  511.         jnc @@v_initl0
  512.  
  513.         mov dx,es                       ; DX = current page table segment
  514.         xor ebx,ebx                     ; index in page dir, also loop counter
  515.         jmp short @@v_initl1f0
  516.  
  517. @@v_initl1:
  518.         xor di,di                       ; clear page table
  519.         mov cx,800h
  520.         xor ax,ax
  521.         rep stosw
  522.  
  523. @@v_initl1f0:
  524.         add dx,100h                     ; increment page table segment
  525.         mov es,dx
  526.  
  527.         lods dword ptr fs:[si]          ; set physical address of page table
  528.         mov gs:[ebx*4],eax              ;  in page directory
  529.  
  530.         inc bx                          ; increment index in page directory
  531.         cmp bl,_pm_pagetables           ; at end of page tables?
  532.         jb @@v_initl1                   ; if no, loop
  533.  
  534. ;-----------------------------------------------------------------------------
  535.         push dx                         ; preserve seg of TSS for later use
  536.  
  537.         xor di,di                       ; clear TSS with all 0, not really
  538.         mov cx,34h                      ;  needed, but just to be safe
  539.         xor ax,ax
  540.         rep stosw
  541.  
  542.         mov eax,vcpi_cr3                ; set CR3 in TSS
  543.         mov es:[1ch],eax
  544.         mov dword ptr es:[64h],680000h  ; set offset of I/O permission bitmap
  545.                                         ;  and clear T bit
  546.         add dx,7                        ; increment next data area ptr
  547.         mov es,dx
  548.  
  549. ;─────────────────────────────────────────────────────────────────────────────
  550. vxr_init:                               ; VCPI/XMS/raw common init tail
  551.         mov ax,es                       ; set IDT base address
  552.         movzx ebx,ax
  553.         shl ebx,4
  554.         mov idtbase,ebx
  555.  
  556.         movzx bx,_pm_rmstacks           ; set top and base of real mode stack
  557.         imul bx,_pm_rmstacklen          ;  area for interrupt redirection
  558.         add ax,80h                      ;  from protected mode
  559.         mov rmstackbase,ax
  560.         add ax,bx
  561.         mov rmstacktop,ax
  562.  
  563.         xor di,di                       ; set up IDT
  564.         mov dx,word ptr picslave
  565.         xor ecx,ecx
  566.  
  567. @@vxr_initl0:
  568.         lea eax,[SELCODE*10000h+ecx*4+off intrmatrix]
  569.         stosd
  570.  
  571.         mov eax,8e00h                   ; interrupt gate type
  572.         mov bl,cl                       ; isolate high 5 bits of int num
  573.         and bl,0f8h
  574.  
  575.         test cl,0f8h                    ; one of the low 8 interrupts?
  576.         jz short @@vxr_initl0f0         ; if yes, store as interrupt gate
  577.  
  578.         cmp bl,dl                       ; one of the high IRQs?
  579.         je short @@vxr_initl0f0         ; if yes, store as interrupt gate
  580.         cmp bl,dh                       ; one of the low IRQs?
  581.         je short @@vxr_initl0f0         ; if yes, store as interrupt gate
  582.  
  583.         or ah,1                         ; set to trap gate type
  584.  
  585. @@vxr_initl0f0:
  586.         stosd
  587.  
  588.         inc cl                          ; increment interrupt number
  589.         jnz @@vxr_initl0                ; loop if more interrupts to go
  590.  
  591.         mov word ptr es:[8*31h],off int31    ; protected mode INT 31h
  592.         mov word ptr es:[8*21h],off int21    ; protected mode INT 21h
  593.  
  594.         mov es,rmstacktop               ; set next data area ptr to end of
  595.                                         ;  real mode stack area
  596. ;-----------------------------------------------------------------------------
  597.     mov ax,es            ; set protected mode stack area base
  598.         movzx eax,ax                    ;  for callbacks
  599.         shl eax,4
  600.     mov pmstackbase,eax
  601.  
  602.         movzx ecx,_pm_pmstacklen        ; set protected mode stack area top
  603.         movzx ebx,_pm_pmstacks          ;  for callbacks
  604.         shl ecx,4
  605.         mov pmstacklen,ecx              ; protected mode stack size in bytes
  606.         imul ebx,ecx
  607.         add ebx,eax
  608.         mov pmstacktop,ebx              ; protected mode stack area top
  609.  
  610.         mov cl,_pm_callbacks            ; CL = number of callbacks
  611.         or cl,cl                        ; any callbacks?
  612.         jz short @@vxr_initf3           ; if no, done with this part
  613.  
  614.         mov callbackbase,ebx            ; top of stacks is base of callbacks
  615.         shr ebx,4                       ; BX = seg of callback area
  616.         mov callbackseg,bx
  617.  
  618.         mov es,bx                       ; ES = seg of callback area
  619.         xor di,di                       ; location within callback seg
  620.  
  621. @@vxr_initl1:
  622.         mov word ptr es:[di],6066h      ; PUSHAD instruction
  623.         mov byte ptr es:[di+2],068h     ; PUSH WORD instruction
  624.         mov word ptr es:[di+3],0        ; immediate 0 used as free flag
  625.         mov word ptr es:[di+5],06866h   ; PUSH DWORD instruction
  626.         mov byte ptr es:[di+11],0b9h    ; MOV CX,? instruction
  627.         mov word ptr es:[di+14],06866h  ; PUSH DWORD instruction
  628.         mov byte ptr es:[di+20],0eah    ; JMP FAR PTR ?:? intruction
  629.         mov word ptr es:[di+21],off callback
  630.         mov word ptr es:[di+23],PMODE_TEXT
  631.  
  632.         add di,25                       ; increment ptr to callback
  633.         dec cl                          ; decrement loop counter
  634.         jnz @@vxr_initl1                ; if more callbacks to do, loop
  635.  
  636.     add di,0fh            ; align next data area on paragraph
  637.     shr di,4
  638.     add bx,di
  639.         mov es,bx                       ; set ES to base of next data area
  640.  
  641. @@vxr_initf3:
  642.  
  643. ;-----------------------------------------------------------------------------
  644.     mov gdtseg,es            ; store segment of GDT
  645.  
  646.         mov ax,es                       ; set GDT base address
  647.         movzx eax,ax
  648.         shl eax,4
  649.         mov gdtbase,eax
  650.  
  651.         mov cx,_pm_selectors            ; set GDT limit
  652.         lea ecx,[8*ecx+8*5+8*SYSSELECTORS-1]
  653.         mov gdtlimit,cx
  654.  
  655.         xor di,di                       ; clear GDT with all 0
  656.         inc cx
  657.         shr cx,1
  658.         xor ax,ax
  659.         rep stosw
  660.  
  661.         cmp pmodetype,2                 ; if under VCPI, do VCPI GDT set up
  662.         jne short @@vxr_initf1
  663.  
  664.         pop ax                          ; restore TSS seg from stack
  665.         movzx eax,ax                    ; set up TSS selector in GDT
  666.         shl eax,4
  667.         mov dword ptr es:[SELVCPITSS+2],eax
  668.         mov byte ptr es:[SELVCPITSS],67h
  669.         mov byte ptr es:[SELVCPITSS+5],89h
  670.  
  671.         add eax,64h-4*9                 ; unused part of TSS is also
  672.         mov vcpiswitchstack,eax         ;  temporary switch stack
  673.  
  674.         mov di,SELVCPICODE              ; copy 3 VCPI descriptors from stack
  675.         mov si,sp                       ;  to GDT
  676.         mov cx,4*3
  677.         rep movs word ptr es:[di],word ptr ss:[si]
  678.  
  679.         add sp,8*3                      ; adjust stack
  680.  
  681. @@vxr_initf1:
  682.         mov word ptr es:[SELZERO],0ffffh; set SELZERO descriptor
  683.         mov word ptr es:[SELZERO+5],0df92h
  684.  
  685.         mov word ptr es:[SELCALLBACKDS],0ffffh  ; set callback DS descriptor
  686.     mov word ptr es:[SELCALLBACKDS+5],0df92h
  687.  
  688.         mov word ptr es:[SELREAL],0ffffh; set real mode attributes descriptor
  689.         mov word ptr es:[SELREAL+5],01092h
  690.  
  691.         mov ax,cs                       ; set SELCODE descriptor (PMODE_TEXT)
  692.         mov bx,SELCODE                  ; BX = index to SELCODE descriptor
  693.         mov cx,0ffffh                   ; CX = limit (64k)
  694.         mov dx,109ah                    ; DX = access rights
  695.         call vxr_initsetdsc
  696.  
  697.         mov bx,8*SYSSELECTORS           ; BX = base of free descriptors
  698.         push bx                         ; store selector
  699.  
  700.         mov ax,ss                       ; set caller SS descriptor
  701.         mov dx,5092h
  702.         call vxr_initsetdsc
  703.  
  704.         mov ax,[bp]                     ; set caller DS descriptor
  705.         mov [bp],bx                     ; put DS selector on stack for exit
  706.         call vxr_initsetdsc
  707.  
  708.         push bx                         ; get PSP segment
  709.         mov ah,51h
  710.         int 21h
  711.         mov si,bx
  712.         pop bx
  713.  
  714.         mov fs,si                       ; set caller environment descriptor
  715.         mov ax,fs:[2ch]
  716.         or ax,ax                        ; is environment seg 0?
  717.         jz short @@vxr_initf0           ; if yes, dont convert to descriptor
  718.         mov fs:[2ch],bx                 ; store selector value in PSP
  719.         call vxr_initsetdsc
  720.  
  721. @@vxr_initf0:
  722.         mov ax,si                       ; set caller PSP descriptor
  723.         mov cx,0ffh                     ; limit is 100h bytes
  724.         call vxr_initsetdsc
  725.  
  726. ;-----------------------------------------------------------------------------
  727.         lea ecx,[ebx-8]                 ; CX = ES descriptor, just set
  728.         pop dx                          ; DX = SS descriptor, from stack
  729.         mov ax,SELZERO                  ; AX = DS descriptor, SELZERO
  730.         movzx ebx,sp                    ; EBX = SP, current SP - same stack
  731.         mov si,SELCODE                  ; target CS is SELCODE, same segment
  732.         mov edi,off @@vxr_initf2        ; target EIP
  733.  
  734.         jmp rmtopmswrout                ; jump to mode switch routine
  735.  
  736. @@vxr_initf2:   
  737.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  738.         mov eax,ds:[4*15h]              ; get INT 15h vector
  739.         mov ds:oldint15vector[edi],eax  ; store INT 15h vector
  740.  
  741.         mov esi,cs:rawextmembase        ; ESI = raw base of extended memory
  742.         cmp esi,cs:rawextmemtop         ; is there any raw extended memory?
  743.         jae dvxr_init                   ; if no, go DPMI/VCPI/XMS/raw init
  744.  
  745.         dw 0b866h,off int15,PMODE_TEXT  ; MOV EAX,PMODE_TEXT:offset int15
  746.         mov ds:[4*15h],eax              ; set new INT 15h handler
  747.  
  748.         mov edi,cs:rawextmemtop         ; EDI = raw top of extended memory
  749.         mov eax,edi                     ; EAX = size of extended memory
  750.         sub eax,esi
  751.         sub eax,10h                     ; subtract memory control block size
  752.         mov [edi-16],eax                ; store size in memory control block
  753.         xor eax,eax
  754.         mov [edi-12],eax                ; no next memory control block
  755.         mov [edi-8],eax                 ; no previous memory control block
  756.         mov [edi-4],al                  ; memory block is free
  757.  
  758.         jmp dvxr_init                   ; go to DPMI/VCPI/XMS/raw init tail
  759.  
  760. ;─────────────────────────────────────────────────────────────────────────────
  761. vxr_initsetdsc:                         ; set descriptor for VCPI/XMS/raw init
  762.         movzx eax,ax                    ; EAX = base of segment
  763.         shl eax,4
  764.         mov word ptr es:[bx],cx         ; limit = CX
  765.         mov dword ptr es:[bx+2],eax     ; base address = EAX
  766.         mov word ptr es:[bx+5],dx       ; access rights = DX
  767.         add bx,8                        ; increment descriptor index
  768.         ret
  769.  
  770. ;═════════════════════════════════════════════════════════════════════════════
  771. x_init:                                 ; XMS protected mode init
  772.         push es                         ; preserve ES, INT 2Fh destroys it
  773.  
  774.         mov ax,4310h                    ; get XMS driver address
  775.         int 2fh
  776.  
  777.         mov xms_callip,bx               ; store XMS driver address
  778.         mov xms_callcs,es
  779.  
  780.         pop es                          ; restore ES (buffer segment)
  781.  
  782.         mov ah,3                        ; enable A20
  783.         call dword ptr xms_callip
  784.  
  785.         mov bx,4                        ; error code 0004h in case of error
  786.         cmp ax,1                        ; error enabling A20?
  787.         jc init_done                    ; if yes, exit with error 0004h
  788.  
  789.         mov si,off int31mxrouttbl       ; set XMS memory allocation functions
  790.  
  791. ;─────────────────────────────────────────────────────────────────────────────
  792. xr_init:                                ; XMS/raw common init tail
  793.         push es                         ; preserve ES, INT 2Fh destroys it
  794.  
  795.         push ds                         ; ES = DS for table copy
  796.         pop es
  797.  
  798.         mov di,off int31mrouttbl        ; copy memory allocation function
  799.         mov cx,5                        ;  addresses to table
  800.         rep movsw
  801.  
  802.         pop es                          ; restore ES (buffer segment)
  803.  
  804.         mov rmtopmswrout,off xr_rmtopmsw; set XMS/raw mode switch addresses
  805.         mov pmtormswrout,off xr_pmtormsw
  806.  
  807.         jmp vxr_init                    ; go to VCPI/XMS/raw continue init
  808.  
  809. ;═════════════════════════════════════════════════════════════════════════════
  810. r_init:                                 ; raw protected mode init
  811.         mov ah,88h                      ; how much extended memory free
  812.         int 15h
  813.  
  814.         mov si,off int31mnrouttbl       ; SI -> no memory allocation functions
  815.         or ax,ax                        ; if none, done with raw init
  816.         jz xr_init
  817.  
  818.         movzx eax,ax                    ; convert AX K to ptr to top of mem
  819.         shl eax,10
  820.         add eax,100000h
  821.         mov cs:rawextmemtop,eax
  822.  
  823.         call enablea20                  ; enable A20
  824.  
  825.         push es                         ; preserve ES (buffer segment)
  826.  
  827.         xor cx,cx                       ; ES -> 0 (interrupt vector table)
  828.         mov es,cx
  829.         les bx,dword ptr es:[4*19h]     ; ES:BX -> int vector table
  830.  
  831.         mov eax,100000h                 ; initial free extended memory base
  832.         cmp dword ptr es:[bx+12h],'SIDV'; VDISK memory allocation?
  833.         jne short @@r_initf0            ; if present, get base of free mem
  834.  
  835.         mov eax,dword ptr es:[bx+2ch]   ; get first free byte of extended mem
  836.         add eax,0fh                     ; align on paragraph
  837.         and eax,0fffff0h                ; address is only 24bit
  838.  
  839. @@r_initf0:
  840.         dec cx                          ; ES -> 0ffffh for ext mem addressing
  841.         mov es,cx
  842.  
  843.         cmp dword ptr es:[13h],'SIDV'   ; VDISK memory allocation?
  844.         jne short @@r_initf1            ; if present, get base of free mem
  845.  
  846.         movzx ebx,word ptr es:[2eh]     ; get first free K of extended memory
  847.         shl ebx,10                      ; adjust K to bytes
  848.  
  849.         cmp eax,ebx                     ; pick larger of 2 addresses
  850.         ja short @@r_initf1
  851.  
  852.         mov eax,ebx
  853.  
  854. @@r_initf1:
  855.         pop es                          ; restore ES (buffer segment)
  856.  
  857.         mov si,off int31mnrouttbl       ; SI -> no memory allocation functions
  858.         cmp eax,cs:rawextmemtop         ; any valid free extended memory
  859.         jae xr_init                     ; if none, done with raw init
  860.  
  861.         mov cs:rawextmembase,eax
  862.         mov si,off int31mrrouttbl       ; set raw memory allocation functions
  863.  
  864.         jmp xr_init                     ; go to XMS/raw continue init
  865.  
  866. ;─────────────────────────────────────────────────────────────────────────────
  867. enablea20:                              ; hardware enable gate A20
  868.         pushf
  869.         push fs gs
  870.         cli
  871.  
  872.         xor ax,ax                       ; set A20 test segments 0 and 0ffffh
  873.         mov fs,ax
  874.         dec ax
  875.         mov gs,ax
  876.  
  877.         call enablea20test              ; is A20 already enabled?
  878.         jz short @@enablea20done        ; if yes, done
  879.  
  880.         in al,92h                       ; PS/2 A20 enable
  881.         or al,2
  882.         jmp short $+2
  883.         jmp short $+2
  884.         jmp short $+2
  885.         out 92h,al
  886.  
  887.         call enablea20test              ; is A20 enabled?
  888.         jz short @@enablea20done        ; if yes, done
  889.  
  890.         call enablea20kbwait            ; AT A20 enable
  891.         jnz short @@enablea20f0
  892.  
  893.         mov al,0d1h
  894.         out 64h,al
  895.  
  896.         call enablea20kbwait
  897.         jnz short @@enablea20f0
  898.  
  899.         mov al,0dfh
  900.         out 60h,al
  901.  
  902.         call enablea20kbwait
  903.  
  904. @@enablea20f0:                          ; wait for A20 to enable
  905.         mov cx,800h                     ; do 800h tries
  906.  
  907. @@enablea20l0:
  908.         call enablea20test              ; is A20 enabled?
  909.         jz @@enablea20done              ; if yes, done
  910.  
  911.         in al,40h                       ; get current tick counter
  912.         jmp short $+2
  913.         jmp short $+2
  914.         jmp short $+2
  915.         in al,40h
  916.         mov ah,al
  917.  
  918. @@enablea20l1:                          ; wait a single tick
  919.         in al,40h
  920.         jmp short $+2
  921.         jmp short $+2
  922.         jmp short $+2
  923.         in al,40h
  924.         cmp al,ah
  925.         je @@enablea20l1
  926.  
  927.         loop @@enablea20l0              ; loop for another try
  928.  
  929.         mov bp,sp                       ; error, A20 did not enable
  930.         mov ax,4                        ; error code 4
  931.         mov word ptr [bp+6],off init_done       ; set init_done return address
  932.  
  933. @@enablea20done:
  934.         pop gs fs
  935.         popf
  936.         ret
  937.  
  938. ;-----------------------------------------------------------------------------
  939. enablea20kbwait:                        ; wait for safe to write to 8042
  940.         xor cx,cx
  941. @@enablea20kbwaitl0:
  942.         jmp short $+2
  943.         jmp short $+2
  944.         jmp short $+2
  945.         in al,64h                       ; read 8042 status
  946.         test al,2                       ; buffer full?
  947.         loopnz @@enablea20kbwaitl0      ; if yes, loop
  948.         ret
  949.  
  950. ;-----------------------------------------------------------------------------
  951. enablea20test:                          ; test for enabled A20
  952.         mov al,fs:[0]                   ; get byte from 0:0
  953.         mov ah,al                       ; preserve old byte
  954.         not al                          ; modify byte
  955.         xchg al,gs:[10h]                ; put modified byte to 0ffffh:10h
  956.         cmp ah,fs:[0]                   ; set zero if byte at 0:0 not modified
  957.         mov gs:[10h],al                 ; put back old byte at 0ffffh:10h
  958.         ret                             ; return, zero if A20 enabled
  959.  
  960. ;═════════════════════════════════════════════════════════════════════════════
  961. int15:                                  ; real mode INT 15h handler
  962.         cmp ah,88h                      ; function 88h?
  963.         je short @@int15f0              ; if yes, need to process
  964.  
  965.         jmp cs:oldint15vector           ; no, go on to old INT 15h handler
  966.  
  967. @@int15f0:
  968.         pushf                           ; call old int 15h handler
  969.         call cs:oldint15vector
  970.  
  971.         sub ax,cs:rawextmemused         ; adjust AX by extended memory used
  972.  
  973.         push bp                         ; clear carry flag on stack for IRET
  974.         mov bp,sp
  975.         and byte ptr [bp+6],0feh
  976.         pop bp
  977.  
  978.         iret                            ; return with new AX extended memory
  979.  
  980. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  981. ; PROTECTED MODE KERNEL CODE
  982. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  983.  
  984. ;═════════════════════════════════════════════════════════════════════════════
  985. v_rmtopmsw:                             ; VCPI real to protected switch
  986.         pushf                           ; store FLAGS
  987.         cli
  988.         push cs                         ; DS = PMODE_TEXT
  989.         pop ds
  990.         pop tempw0                      ; move FLAGS from stack to temp
  991.         mov tempw1,ax                   ; store AX (protected mode DS)
  992.         mov tempw2,si                   ; store SI (protected mode CS)
  993.         mov esi,vcpistrucaddx           ; ESI = linear addx of VCPI structure
  994.         mov ax,0de0ch                   ; VCPI switch to protected mode
  995.         int 67h
  996. v_rmtopmswpm:
  997.         mov ss,dx                       ; load protected mode SS:ESP
  998.         mov esp,ebx
  999.         mov ds,cs:tempw1                ; load protected mode DS
  1000.         mov es,cx                       ; load protected mode ES
  1001.         xor ax,ax
  1002.         mov fs,ax                       ; load protected mode FS with NULL
  1003.         mov gs,ax                       ; load protected mode GS with NULL
  1004.         pushfd                          ; store EFLAGS
  1005.         mov ax,cs:tempw0                ; move bits 0-11 of old FLAGS onto
  1006.         and ah,0fh                      ;  stack for IRETD
  1007.         mov [esp],ax
  1008.         push cs:tempd1                  ; store protected mode target CS
  1009.         push edi                        ; store protected mode target EIP
  1010.         iretd                           ; go to targed addx in protected mode
  1011.  
  1012. ;═════════════════════════════════════════════════════════════════════════════
  1013. v_pmtormsw:                             ; VCPI protected to real switch
  1014.         pushf                           ; store FLAGS
  1015.         cli
  1016.         push ax                         ; store AX (real mode DS)
  1017.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1018.         movzx ebx,bx                    ; clear high word of EBX, real mode SP
  1019.         movzx edx,dx                    ; clear high word of EDX, real mode SS
  1020.         mov eax,cs:vcpiswitchstack      ; EAX -> top of temporary switch stack
  1021.         mov dword ptr ds:[eax+32],0     ; store real mode GS
  1022.         mov dword ptr ds:[eax+28],0     ; store real mode FS
  1023.         movzx ecx,cx                    ; clear high word of ECX, real mode ES
  1024.         mov ds:[eax+20],ecx             ; store real mode ES
  1025.         pop cx                          ; move real mode DS from protected
  1026.         mov ds:[eax+24],ecx             ;  mode stack to VCPI call stack
  1027.         mov ds:[eax+16],edx             ; store real mode SS
  1028.         mov ds:[eax+12],ebx             ; store real mode SP
  1029.         mov dword ptr ds:[eax+4],PMODE_TEXT             ; store real mode CS
  1030.         mov dword ptr ds:[eax+0],off @@v_pmtormswf0     ; store real mode IP
  1031.         pop bx                          ; restore FLAGS from stack
  1032.         mov ss,cs:selzero               ; SS -> 0 (beginning of memory)
  1033.         mov esp,eax                     ; ESP = stack ptr for VCPI call
  1034.         mov ax,0de0ch                   ; VCPI switch to real mode (V86)
  1035.     call fword ptr cs:vcpi_calleip
  1036. @@v_pmtormswf0:
  1037.         push bx                         ; store old FLAGS
  1038.     push si             ; store target CS in real mode
  1039.     push di             ; store target IP in real mode
  1040.     iret                ; go to target addx in real mode
  1041.  
  1042. ;═════════════════════════════════════════════════════════════════════════════
  1043. xr_rmtopmsw:                            ; XMS/raw real to protected switch
  1044.         pushfd                          ; store EFLAGS
  1045.         cli
  1046.         push ax                         ; store AX (protected mode DS)
  1047.         lidt fword ptr cs:idtlimit      ; load protected mode IDT
  1048.         lgdt fword ptr cs:gdtlimit      ; load protected mode GDT
  1049.         mov eax,cr0                     ; switch to protected mode
  1050.         or al,1
  1051.         mov cr0,eax
  1052.         db 0eah                         ; JMP FAR PTR SELCODE:$+4
  1053.         dw $+4,SELCODE                  ;  (clear prefetch que)
  1054.         pop ds                          ; load protected mode DS
  1055.         mov es,cx                       ; load protected mode ES
  1056.         xor ax,ax
  1057.         mov fs,ax                       ; load protected mode FS with NULL
  1058.         mov gs,ax                       ; load protected mode GS with NULL
  1059.         pop eax
  1060.         mov ss,dx                       ; load protected mode SS:ESP
  1061.         mov esp,ebx
  1062.         and ah,0bfh                     ; set NT=0 in old EFLAGS
  1063.         push ax                         ; set current FLAGS
  1064.         popf
  1065.         push eax                        ; store old EFLAGS
  1066.         push esi                        ; store protected mode target CS
  1067.         push edi                        ; store protected mode target EIP
  1068.         iretd                           ; go to targed addx in protected mode
  1069.  
  1070. ;═════════════════════════════════════════════════════════════════════════════
  1071. xr_pmtormsw:                            ; XMS/raw protected to real switch
  1072.         push cx                         ; store CX (real mode ES)
  1073.         pushf                           ; store FLAGS
  1074.         cli
  1075.         push ax                         ; store AX (real mode DS)
  1076.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1077.         mov ecx,cs:codebase             ; get offset of PMODE_TEXT from 0
  1078.         pop ds:tempw0[ecx]              ; move real mode DS from stack to temp
  1079.         pop ds:tempw1[ecx]              ; move FLAGS from stack to temp
  1080.         pop cx                          ; restore CX (real mode ES)
  1081.         mov ax,SELREAL                  ; load descriptors with real mode seg
  1082.         mov ds,ax                       ;  attributes
  1083.         mov es,ax
  1084.         mov fs,ax
  1085.         mov gs,ax
  1086.         mov ss,ax                       ; load descriptor with real mode attr
  1087.         movzx esp,bx                    ; load real mode SP, high word 0
  1088.         lidt fword ptr cs:rmidtlimit    ; load real mode IDT
  1089.         mov eax,cr0                     ; switch to real mode
  1090.         and al,0feh
  1091.         mov cr0,eax
  1092.         db 0eah                         ; JMP FAR PTR PMODE_TEXT:$+4
  1093.         dw $+4,PMODE_TEXT               ;  (clear prefetch que)
  1094.         mov ss,dx                       ; load real mode SS
  1095.         mov ds,cs:tempw0                ; load real mode DS
  1096.         mov es,cx                       ; load real mode ES
  1097.         xor ax,ax
  1098.         mov fs,ax                       ; load real mode FS with NULL
  1099.         mov gs,ax                       ; load real mode GS with NULL
  1100.         push cs:tempw1                  ; store old FLAGS
  1101.         push si                         ; store real mode target CS
  1102.         push di                         ; store real mode target IP
  1103.         iret                            ; go to target addx in real mode
  1104.  
  1105. ;═════════════════════════════════════════════════════════════════════════════
  1106. vxr_saverestorerm:                      ; VCPI/XMS/raw save/restore status
  1107.         retf                            ; no save/restore needed, 16bit RETF
  1108.  
  1109. ;═════════════════════════════════════════════════════════════════════════════
  1110. vxr_saverestorepm:                      ; VCPI/XMS/raw save/restore status
  1111.         db 66h,0cbh                     ; no save/restore needed, 32bit RETF
  1112.  
  1113. ;═════════════════════════════════════════════════════════════════════════════
  1114. critical_error:                         ; some unrecoverable error
  1115.         cli                             ; make sure we are not interrupted
  1116.         in al,61h                       ; beep
  1117.         or al,3
  1118.         out 61h,al
  1119.         jmp $                           ; now hang
  1120.  
  1121. ;═════════════════════════════════════════════════════════════════════════════
  1122. callback:                               ; real mode callback handler
  1123.         mov ax,sp                       ; preserve SS:SP for callback
  1124.         push ss
  1125.         push ax
  1126.  
  1127.         push gs fs ds es                ; preserve real mode regs for callback
  1128.         pushf                           ; preserve FLAGS for callback
  1129.  
  1130.         cli
  1131.         cld
  1132.  
  1133.         mov ebp,cs:pmstacktop           ; EBP = ESP for protected mode
  1134.  
  1135.         mov ebx,ebp                     ; set EBX to next stack location
  1136.         sub ebx,cs:pmstacklen
  1137.         mov cs:pmstacktop,ebx           ; update ptr for possible reenterancy
  1138.  
  1139.         cmp ebx,cs:pmstackbase          ; exceeded protected mode stack space?
  1140.         jb critical_error               ; if yes, critical error (hang)
  1141.  
  1142.         xor eax,eax                     ; EAX = base address of SS
  1143.         mov ax,ss
  1144.         shl eax,4
  1145.  
  1146.     movzx ebx,sp            ; EBX = current linear SS:SP
  1147.         add ebx,eax
  1148.  
  1149.     mov es,cs:gdtseg        ; set for protected mode callback DS
  1150.     or eax,92000000h        ;  base address in GDT
  1151.         mov es:[SELCALLBACKDS+2],eax
  1152.  
  1153.         mov ax,SELZERO                  ; DS selector for protected mode
  1154.         mov dx,ax                       ; SS selector = DS selector
  1155.         mov si,SELCODE                  ; target protected mode CS:EIP
  1156.         mov edi,offset @@callbackf0
  1157.  
  1158.         jmp cs:rmtopmswrout             ; go to protected mode
  1159.  
  1160. @@callbackf0:
  1161.         mov edi,[esp+14]                ; EDI -> register structure from stack
  1162.  
  1163.         lea esi,[esp+24]                ; copy general registers from stack
  1164.         mov ecx,8                       ;  to register structure
  1165.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  1166.  
  1167.         mov esi,esp                     ; copy FLAGS, ES, DS, FG, and GS
  1168.         movs word ptr es:[edi],word ptr ds:[esi]
  1169.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1170.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1171.  
  1172.         lods dword ptr ds:[esi]         ; EAX = real mode SS:SP from stack
  1173.         add ax,42                       ; adjust SP for stuff on stack
  1174.         mov es:[edi+4],eax              ; put in register structure
  1175.  
  1176.         mov ds,cs:selcallbackds         ; DS = callback DS selector
  1177.         sub edi,42                      ; EDI -> register structure
  1178.         movzx esi,ax                    ; ESI = old real mode SP
  1179.         xchg esp,ebp                    ; ESP = protected mode stack
  1180.  
  1181.         pushfd                          ; push flags for IRETD from callback
  1182.         db 66h                          ; push 32bit CS for IRETD
  1183.         push cs
  1184.         dw 6866h,@@callbackf1,0         ; push 32bit EIP for IRETD
  1185.  
  1186.         movzx eax,word ptr [ebp+22]     ; EAX = target CS of callback
  1187.         push eax                        ; push 32bit CS for RETF to callback
  1188.         push dword ptr [ebp+18]         ; push 32bit EIP for retf
  1189.  
  1190.         db 66h                          ; 32bit RETF to callback
  1191.         retf
  1192.  
  1193. @@callbackf1:
  1194.         cli
  1195.         cld
  1196.  
  1197.         push es                         ; DS:ESI = register structure
  1198.         pop ds
  1199.         mov esi,edi
  1200.  
  1201.         mov es,cs:selzero               ; ES -> 0 (beginning of memory)
  1202.  
  1203.         movzx ebx,word ptr [esi+2eh]    ; EBX = real mode SP from structure
  1204.         movzx edx,word ptr [esi+30h]    ; EDX = real mode SS from structure
  1205.         sub bx,42                       ; subtract size of vars to be put
  1206.  
  1207.         mov ebp,[esi+0ch]               ; EBP = pushed ESP from real mode
  1208.         mov bp,bx                       ; EBP = old high & new low word of ESP
  1209.  
  1210.         lea edi,[edx*4]                 ; EDI -> real mode base of stack
  1211.         lea edi,[edi*4+ebx]             ;  of vars to be stored
  1212.  
  1213.         mov ecx,8                       ; copy general registers to stack
  1214.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  1215.  
  1216.         mov eax,[esi+6]                 ; EAX = return FS and GS for real mode
  1217.         mov es:[edi],eax                ; store on real mode stack for return
  1218.  
  1219.         mov ax,[esi]                    ; AX = return FLAGS for real mode
  1220.         mov es:[edi+8],ax               ; store on real mode stack for return
  1221.         mov eax,[esi+10]                ; EAX = return CS:IP for real mode
  1222.         mov es:[edi+4],eax              ; store on real mode stack for return
  1223.  
  1224.         mov ax,[esi+4]                  ; AX = return DS for real mode
  1225.         mov cx,[esi+2]                  ; CX = return ES for real mode
  1226.  
  1227.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1228.         mov di,off @@callbackf2
  1229.  
  1230.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1231.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1232.  
  1233. @@callbackf2:
  1234.         mov esp,ebp                     ; restore total ESP, old high word
  1235.  
  1236.         mov eax,cs:pmstacklen           ; restore top of protected mode stack
  1237.         add cs:pmstacktop,eax
  1238.  
  1239.         popad                           ; get callback return general regs
  1240.         pop fs gs                       ; get callback return FS and GS values
  1241.         iret                            ; go to callback return CS:IP
  1242.  
  1243. ;═════════════════════════════════════════════════════════════════════════════
  1244. intrmatrix:                ; INT redirectors for all INTs
  1245. rept 100h
  1246.         call near ptr intr              ; 3 byte CALL
  1247.         nop                             ; 1 byte NOP to align on 4
  1248. endm
  1249.  
  1250. ;═════════════════════════════════════════════════════════════════════════════
  1251. intr:                                   ; general interrupt redirector
  1252.         cli
  1253.         sub esp,2
  1254.         xchg eax,[esp]                  ; store EAX, also get CALL address
  1255.         push ecx edx ebx esp ebp esi edi; store rest of registers for POPAD
  1256.         push ds es fs gs
  1257.  
  1258.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1259.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  1260.  
  1261.         mov dx,cs:rmstacktop            ; DX = SS for real mode redirection
  1262.         movzx ebp,dx                    ; EBP -> top of real mode stack
  1263.         shl ebp,4
  1264.  
  1265.         mov bx,cs:_pm_rmstacklen        ; get size of real mode stack
  1266.         sub dx,bx                       ; adjust DX to next stack location
  1267.         mov ds:rmstacktop[edi],dx       ; update ptr for possible reenterancy
  1268.         shl bx,4                        ; set real mode SP to top of stack
  1269.  
  1270.         cmp dx,cs:rmstackbase           ; exceeded real mode stack space?
  1271.         jb critical_error               ; if yes, critical error (hang)
  1272.  
  1273.         mov ds:[ebp-2],ss               ; store SS:ESP on real mode stack
  1274.         mov ds:[ebp-6],esp
  1275.  
  1276.         shr eax,16                      ; move CALL address to AX
  1277.         sub ax,off intrmatrix           ; AX = int number, since AX is:
  1278.         shr ax,2                        ;  intrmatrix + (int number * 4)
  1279.  
  1280.         mov ah,al                       ; AH = high 5 bits of int number
  1281.         and ah,0f8h
  1282.  
  1283.         cmp ah,cs:picslave              ; high IRQ?
  1284.         je short intrirq                ; if yes, do IRQ
  1285.         cmp ah,cs:picmaster             ; low IRQ?
  1286.         jne short intrint               ; if no, do INT (with general regs)
  1287.  
  1288. ;-----------------------------------------------------------------------------
  1289. intrirq:                                ; an IRQ redirection
  1290.         mov ds:@@intrirqintnum[edi],al  ; modify code with interrupt number
  1291.  
  1292.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1293.         mov di,off @@intrirqf0
  1294.         sub bx,6                        ; adjust real mode SP for stored vars
  1295.  
  1296.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1297.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1298.  
  1299. @@intrirqf0:
  1300.         db 0cdh                         ; INT @@intrirqintnum
  1301. @@intrirqintnum db      ?
  1302.  
  1303.         mov ax,SELZERO                  ; DS selector value for protected mode
  1304.         mov cx,ax                       ; ES selector value for protected mode
  1305.         pop ebx                         ; get protected mode SS:ESP from stack
  1306.         pop dx
  1307.         mov si,SELCODE                  ; target CS:EIP in protected mode
  1308.         mov edi,off @@intrirqf1
  1309.  
  1310.         jmp cs:rmtopmswrout             ; go back to protected mode
  1311.  
  1312. @@intrirqf1:
  1313.         mov edi,cs:codebase             ; restore top of real mode stack
  1314.         mov ax,cs:_pm_rmstacklen
  1315.         add ds:rmstacktop[edi],ax
  1316.  
  1317.         pop gs fs es ds                 ; restore all registers
  1318.         popad
  1319.         iretd
  1320.  
  1321. ;-----------------------------------------------------------------------------
  1322. intrint:                                ; an INT redirection
  1323.         mov ds:@@intrintintnum[edi],al  ; modify code with interrupt number
  1324.  
  1325.         mov es,cs:selzero               ; copy registers from protected mode
  1326.         lea edi,[ebp-26h]               ;  stack to real mode stack
  1327.         lea esi,[esp+8]
  1328.         mov ecx,8
  1329.         cld
  1330.         rep movs dword ptr es:[edi],dword ptr ss:[esi]
  1331.  
  1332.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1333.         mov di,off @@intrintf0
  1334.         sub bx,26h                      ; adjust real mode SP for stored vars
  1335.  
  1336.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1337.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1338.  
  1339. @@intrintf0:
  1340.         popad                           ; load regs with int call values
  1341.  
  1342.         db 0cdh                         ; INT @@intrirqintnum
  1343. @@intrintintnum db      ?
  1344.  
  1345.         pushad                          ; store registers on stack
  1346.         pushf                           ; store flags on stack
  1347.         cli
  1348.  
  1349.         xor eax,eax                     ; EAX = linear ptr to SS
  1350.         mov ax,ss
  1351.         shl eax,4
  1352.         movzx ebp,sp                    ; EBP = SP
  1353.  
  1354.         mov ebx,[bp+22h]                ; get protected mode SS:ESP from stack
  1355.         mov dx,[bp+26h]
  1356.  
  1357.         add ebp,eax                     ; EBP -> stored regs on stack
  1358.  
  1359.         mov ax,SELZERO                  ; DS selector value for protected mode
  1360.         mov cx,ax                       ; ES selector value for protected mode
  1361.         mov si,SELCODE                  ; target CS:EIP in protected mode
  1362.         mov edi,off @@intrintf1
  1363.  
  1364.         jmp cs:rmtopmswrout             ; go back to protected mode
  1365.  
  1366. @@intrintf1:
  1367.         mov edi,cs:codebase             ; restore top of real mode stack
  1368.         mov ax,cs:_pm_rmstacklen
  1369.         add ds:rmstacktop[edi],ax
  1370.  
  1371.         mov ax,ds:[ebp]                 ; move return FLAGS from real mode
  1372.         and ax,8d5h                     ;  stack to protected mode stack
  1373.         mov bx,[esp+30h]
  1374.         and bx,not 8d5h
  1375.         or ax,bx
  1376.         mov [esp+30h],ax
  1377.  
  1378.         mov edi,ds:[ebp+2]              ; restore return registers from real
  1379.         mov esi,ds:[ebp+6]              ;  mode stack
  1380.         mov ebx,ds:[ebp+18]
  1381.         mov edx,ds:[ebp+22]
  1382.         mov ecx,ds:[ebp+26]
  1383.         mov eax,ds:[ebp+30]
  1384.         mov ebp,ds:[ebp+10]
  1385.  
  1386.         pop gs fs es ds                 ; restore segment regs
  1387.         add esp,20h                     ; skip old general registers on stack
  1388.         iretd
  1389.  
  1390. ;═════════════════════════════════════════════════════════════════════════════
  1391. int21:                                  ; watch for INT 21h AH=4Ch
  1392.         cmp ah,4ch                      ; AH = 4Ch?
  1393.         jne intrmatrix+4*21h            ; if no, go to INT 21h redirection
  1394.  
  1395.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1396.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  1397.  
  1398.         mov ebx,cs:oldint15vector       ; put back old INT 15h handler
  1399.         mov ds:[4*15h],ebx
  1400.  
  1401.         jmp intrmatrix+4*21h            ; go to INT 21h redirection
  1402.  
  1403. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1404. ; INT 31h INTERFACE
  1405. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1406.  
  1407. ;═════════════════════════════════════════════════════════════════════════════
  1408. int31:                                  ; protected mode INT 31h handler
  1409.         cli
  1410.         cld
  1411.         push ds es fs gs                ; push regs needed
  1412.         pushad
  1413.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1414.  
  1415.         push bx
  1416.         mov bx,(INT31FUNCNUM - 1) * 2   ; number of functions to check
  1417. @@int31l0:
  1418.         cmp ax,cs:int31functbl[bx]      ; found function value?
  1419.         jne short @@int31l0c
  1420.  
  1421.         mov bx,cs:int31routtbl[bx]      ; yes, go to appropriate handler
  1422.         xchg bx,[esp]
  1423.         ret
  1424.  
  1425. @@int31l0c:
  1426.         sub bx,2                        ; no, continue loop
  1427.         jnc @@int31l0
  1428.  
  1429.         pop bx                          ; no function found
  1430.         jmp int31fail8001               ; error 8001h
  1431.  
  1432. ;-----------------------------------------------------------------------------
  1433. int31fail8024:                          ; INT 31h return fail with error 8024h
  1434.         mov word ptr [esp+28],8024h     ; set AX on stack to 8024h for POPAD
  1435.         jmp short int31fail
  1436.  
  1437. ;-----------------------------------------------------------------------------
  1438. int31fail8023:                          ; INT 31h return fail with error 8023h
  1439.         mov word ptr [esp+28],8023h     ; set AX on stack to 8023h for POPAD
  1440.         jmp short int31fail
  1441.  
  1442. ;-----------------------------------------------------------------------------
  1443. int31fail8022:                          ; INT 31h return fail with error 8022h
  1444.         mov word ptr [esp+28],8022h     ; set AX on stack to 8022h for POPAD
  1445.         jmp short int31fail
  1446.  
  1447. ;-----------------------------------------------------------------------------
  1448. int31fail8021:                          ; INT 31h return fail with error 8021h
  1449.         mov word ptr [esp+28],8021h     ; set AX on stack to 8021h for POPAD
  1450.         jmp short int31fail
  1451.  
  1452. ;-----------------------------------------------------------------------------
  1453. int31fail8016:                          ; INT 31h return fail with error 8016h
  1454.         mov word ptr [esp+28],8016h     ; set AX on stack to 8016h for POPAD
  1455.         jmp short int31fail
  1456.  
  1457. ;-----------------------------------------------------------------------------
  1458. int31fail8015:                          ; INT 31h return fail with error 8015h
  1459.         mov word ptr [esp+28],8015h     ; set AX on stack to 8015h for POPAD
  1460.         jmp short int31fail
  1461.  
  1462. ;-----------------------------------------------------------------------------
  1463. int31fail8013:                          ; INT 31h return fail with error 8013h
  1464.         mov word ptr [esp+28],8013h     ; set AX on stack to 8013h for POPAD
  1465.         jmp short int31fail
  1466.  
  1467. ;-----------------------------------------------------------------------------
  1468. int31fail8012:                          ; INT 31h return fail with error 8012h
  1469.         mov word ptr [esp+28],8012h     ; set AX on stack to 8012h for POPAD
  1470.         jmp short int31fail
  1471.  
  1472. ;-----------------------------------------------------------------------------
  1473. int31fail8011:                          ; INT 31h return fail with error 8011h
  1474.         mov word ptr [esp+28],8011h     ; set AX on stack to 8011h for POPAD
  1475.         jmp short int31fail
  1476.  
  1477. ;-----------------------------------------------------------------------------
  1478. int31fail8010:                          ; INT 31h return fail with error 8010h
  1479.         mov word ptr [esp+28],8010h     ; set AX on stack to 8010h for POPAD
  1480.         jmp short int31fail
  1481.  
  1482. ;-----------------------------------------------------------------------------
  1483. int31fail8001:                          ; INT 31h return fail with error 8001h
  1484.         mov word ptr [esp+28],8001h     ; set AX on stack to 8001h for POPAD
  1485.         jmp short int31fail
  1486.  
  1487. ;-----------------------------------------------------------------------------
  1488. int31failcx:                            ; INT 31h return fail with CX,AX
  1489.         mov word ptr [esp+24],cx        ; put CX onto stack for POPAD
  1490.  
  1491. ;-----------------------------------------------------------------------------
  1492. int31failax:                            ; INT 31h return fail with AX
  1493.         mov word ptr [esp+28],ax        ; put AX onto stack for POPAD
  1494.  
  1495. ;-----------------------------------------------------------------------------
  1496. int31fail:                              ; INT 31h return fail, pop all regs
  1497.         popad
  1498.         pop gs fs es ds
  1499.  
  1500. ;-----------------------------------------------------------------------------
  1501. int31failnopop:                         ; INT 31h return fail with carry set
  1502.         or byte ptr [esp+8],1           ; set carry in EFLAGS on stack
  1503.         iretd
  1504.  
  1505. ;-----------------------------------------------------------------------------
  1506. int31okdx:                              ; INT 31h return ok with DX,CX,AX
  1507.         mov [esp+20],dx                 ; put CX onto stack for POPAD
  1508.         jmp short int31okcx
  1509.  
  1510. ;-----------------------------------------------------------------------------
  1511. int31oksinoax:                          ; INT 31h return ok SI,DI,BX,CX
  1512.         mov ax,[esp+28]                 ; get old value of AX for restore
  1513.  
  1514. ;-----------------------------------------------------------------------------
  1515. int31oksi:                              ; INT 31h return ok SI,DI,BX,CX,AX
  1516.         mov [esp+4],si                  ; put SI onto stack for POPAD
  1517.         mov [esp],di                    ; put DI onto stack for POPAD
  1518.         mov [esp+16],bx                 ; put BX onto stack for POPAD
  1519.  
  1520. ;-----------------------------------------------------------------------------
  1521. int31okcx:                              ; INT 31h return ok with CX,AX
  1522.         mov [esp+24],cx                 ; put CX onto stack for POPAD
  1523.  
  1524. ;-----------------------------------------------------------------------------
  1525. int31okax:                              ; INT 31h return ok with AX
  1526.         mov [esp+28],ax                 ; put AX onto stack for POPAD
  1527.  
  1528. ;-----------------------------------------------------------------------------
  1529. int31ok:                                ; INT 31h return ok, pop all regs
  1530.         popad
  1531.         pop gs fs es ds
  1532.  
  1533. ;-----------------------------------------------------------------------------
  1534. int31oknopop:                           ; INT 31h return ok with carry clear
  1535.         and byte ptr [esp+8],0feh       ; clear carry in EFLAGS on stack
  1536.         iretd
  1537.  
  1538. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1539. ; DESCRIPTOR FUNCTIONS
  1540. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1541.  
  1542. ;-----------------------------------------------------------------------------
  1543. int31testsel:                           ; test for valid selector BX
  1544.         pop bp                          ; pop return address
  1545.  
  1546.         cmp bx,cs:gdtlimit              ; selector BX out of range?
  1547.         ja int31fail8022                ; if yes, fail with error 8022h
  1548.  
  1549.         mov edi,cs:gdtbase              ; get base of GDT
  1550.         and bl,0f8h                     ; mask offset table index and RPL
  1551.         movzx ebx,bx                    ; EBX = selector index
  1552.         test byte ptr ds:[edi+ebx+6],10h; is descriptor used?
  1553.         jz int31fail8022                ; if descriptor not used, fail 8022h
  1554.  
  1555.         jmp bp                          ; return ok
  1556.  
  1557. ;-----------------------------------------------------------------------------
  1558. int31testaccess:                        ; test access bits in CX
  1559.         pop bp                          ; pop return address
  1560.  
  1561.         test ch,20h                     ; test MUST BE 0 bit in CH
  1562.         jnz int31fail8021               ; if not 0, error 8021h
  1563.  
  1564.         test cl,90h                     ; test present and MUST BE 1 bits
  1565.         jz int31fail8021                ; if both 0, error 8021h
  1566.         jpo int31fail8021               ; if unequal, error 8021h
  1567.  
  1568.         test cl,60h                     ; test DPL
  1569.         jnz int31fail8021               ; if not 0, error 8021h
  1570.  
  1571.         test cl,8                       ; if code, more tests needed
  1572.         jz short @@int31testselok       ; if data, skip code tests
  1573.  
  1574.         test cl,6                       ; test conforming and readable bits
  1575.         jz int31fail8021                ; if both 0, error 8021h
  1576.         jpe int31fail8021               ; if equal, error 8021h
  1577.  
  1578. @@int31testselok:
  1579.         jmp bp                          ; return ok
  1580.  
  1581. ;─────────────────────────────────────────────────────────────────────────────
  1582. int310000:                              ; allocate descriptors
  1583.         or cx,cx                        ; if CX = 0, error 8021h
  1584.         jz int31fail8021
  1585.  
  1586.         mov edx,cs:gdtbase              ; get base of GDT
  1587.         movzx eax,cs:gdtlimit           ; EAX = last selector index
  1588.         and al,0f8h
  1589.  
  1590.         mov bx,cx                       ; BX = number of selectors to find
  1591. @@int310000l0:
  1592.         test byte ptr ds:[edx+eax+6],10h; is descriptor used?
  1593.         jnz short @@int310000l0f0
  1594.  
  1595.         dec bx                          ; found free descriptor, dec counter
  1596.         jnz short @@int310000l0f1       ; continue if need to find more
  1597.  
  1598.         mov ebx,eax                     ; found all descriptors requested
  1599. @@int310000l1:
  1600.         mov dword ptr ds:[edx+ebx],0    ; set entire new descriptor
  1601.         mov dword ptr ds:[edx+ebx+4],109200h
  1602.         add bx,8                        ; increment selector index
  1603.         dec cx                          ; dec counter of descriptors to mark
  1604.         jnz @@int310000l1               ; loop if more to mark
  1605.  
  1606.         jmp int31okax                   ; return ok, with AX
  1607.  
  1608. @@int310000l0f0:
  1609.         mov bx,cx                       ; reset number of selectors to find
  1610.  
  1611. @@int310000l0f1:
  1612.         sub ax,8                        ; dec current selector counter
  1613.         cmp ax,8*SYSSELECTORS           ; more descriptors to go?
  1614.         jae @@int310000l0               ; if yes, loop
  1615.  
  1616.         jmp int31fail8011               ; did not find descriptors
  1617.  
  1618. ;─────────────────────────────────────────────────────────────────────────────
  1619. int310001:                              ; free descriptor
  1620.         call int31testsel               ; test for valid selector BX
  1621.  
  1622.         and byte ptr ds:[edi+ebx+6],0efh; mark descriptor as free
  1623.  
  1624.         mov cx,4                        ; zero any segregs loaded with BX
  1625.         lea ebp,[esp+32]                ; EBP -> selectors on stack
  1626. @@int310001l0:
  1627.         cmp word ptr [ebp],bx           ; selector = BX?
  1628.         jne short @@int310001l0f0       ; if no, continue loop
  1629.  
  1630.         mov word ptr [ebp],0            ; zero selector on stack
  1631.  
  1632. @@int310001l0f0:
  1633.         add ebp,2                       ; increment selector ptr
  1634.         loop @@int310001l0              ; loop
  1635.  
  1636.         jmp int31ok                     ; return ok
  1637.  
  1638. ;─────────────────────────────────────────────────────────────────────────────
  1639. int310003:                              ; get selector increment value
  1640.         mov ax,8                        ; selector increment value is 8
  1641.         jmp int31okax                   ; return ok, with AX
  1642.  
  1643. ;─────────────────────────────────────────────────────────────────────────────
  1644. int310006:                              ; get segment base address
  1645.         call int31testsel               ; test for valid selector BX
  1646.  
  1647.         mov dx,word ptr ds:[edi+ebx+2]  ; low word of 32bit linear address
  1648.         mov cl,byte ptr ds:[edi+ebx+4]  ; high word of 32bit linear address
  1649.         mov ch,byte ptr ds:[edi+ebx+7]
  1650.  
  1651.         jmp int31okdx                   ; return ok, with DX, CX, AX
  1652.  
  1653. ;─────────────────────────────────────────────────────────────────────────────
  1654. int310007:                              ; set segment base address
  1655.         call int31testsel               ; test for valid selector BX
  1656.  
  1657.         mov word ptr ds:[edi+ebx+2],dx  ; low word of 32bit linear address
  1658.         mov byte ptr ds:[edi+ebx+4],cl  ; high word of 32bit linear address
  1659.         mov byte ptr ds:[edi+ebx+7],ch
  1660.  
  1661.         jmp int31ok                     ; return ok
  1662.  
  1663. ;─────────────────────────────────────────────────────────────────────────────
  1664. int310008:                              ; set segment limit
  1665.         call int31testsel               ; test for valid selector BX
  1666.  
  1667.         cmp cx,0fh                      ; limit greater than 1M?
  1668.         jbe short @@int310008f0
  1669.  
  1670.         mov ax,dx                       ; yup, limit greater than 1M
  1671.         and ax,0fffh
  1672.         cmp ax,0fffh                    ; low 12 bits set?
  1673.         jne int31fail8021               ; if no, error 8021h
  1674.  
  1675.         shrd dx,cx,12                   ; DX = low 16 bits of page limit
  1676.         shr cx,12                       ; CL = high 4 bits of page limit
  1677.         or cl,80h                       ; set granularity bit in CL
  1678.  
  1679. @@int310008f0:
  1680.         mov word ptr ds:[edi+ebx],dx    ; put low word of limit
  1681.         and byte ptr ds:[edi+ebx+6],70h ; mask off G and high nybble of limit
  1682.         or byte ptr ds:[edi+ebx+6],cl   ; put high nybble of limit
  1683.  
  1684.         jmp int31ok                     ; return ok
  1685.  
  1686. ;─────────────────────────────────────────────────────────────────────────────
  1687. int310009:                              ; set descriptor access rights
  1688.         call int31testsel               ; test for valid selector BX
  1689.  
  1690.         call int31testaccess            ; test access bits in CX
  1691.  
  1692.         or ch,10h                       ; set AVL bit, descriptor used
  1693.         and ch,0f0h                     ; mask off low nybble of CH
  1694.         and byte ptr ds:[edi+ebx+6],0fh ; mask off high nybble access rights
  1695.         or byte ptr ds:[edi+ebx+6],ch   ; or in high access rights byte
  1696.         mov byte ptr ds:[edi+ebx+5],cl  ; put low access rights byte
  1697.  
  1698.         jmp int31ok                     ; return ok
  1699.  
  1700. ;─────────────────────────────────────────────────────────────────────────────
  1701. int31000a:                              ; create alias descriptor
  1702.         call int31testsel               ; test for valid selector BX
  1703.  
  1704.         mov ax,0000h                    ; allocate descriptor
  1705.         mov cx,1
  1706.         int 31h
  1707.         jc int31fail8011                ; if failed, descriptor unavailable
  1708.  
  1709.         push ax                         ; preserve allocated selector
  1710.  
  1711.         push ds                         ; copy descriptor and set type data
  1712.         pop es
  1713.         movzx edi,ax                    ; EDI = target selector
  1714.         mov esi,cs:gdtbase              ; ESI -> GDT
  1715.         add edi,esi                     ; adjust to target descriptor in GDT
  1716.         add esi,ebx                     ; adjust to source descriptor in GDT
  1717.  
  1718.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1719.         lods dword ptr ds:[esi]
  1720.         mov ah,92h                      ; set descriptor type - R/W up data
  1721.         stos dword ptr es:[edi]
  1722.  
  1723.         pop ax                          ; restore allocated selector
  1724.  
  1725.         jmp int31okax                   ; return ok, with AX
  1726.  
  1727. ;─────────────────────────────────────────────────────────────────────────────
  1728. int31000b:                              ; get descriptor
  1729.         call int31testsel               ; test for valid selector BX
  1730.  
  1731.         lea esi,[edi+ebx]               ; ESI -> descriptor in GDT
  1732.         mov edi,[esp]                   ; get EDI buffer ptr from stack
  1733.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1734.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1735.  
  1736.         jmp int31ok                     ; return ok
  1737.  
  1738. ;─────────────────────────────────────────────────────────────────────────────
  1739. int31000c:                              ; set descriptor
  1740.         call int31testsel               ; test for valid selector BX
  1741.  
  1742.         mov esi,[esp]                   ; ESI = EDI buffer ptr from stack
  1743.         mov cx,es:[esi+5]               ; get access rights from descriptor
  1744.         call int31testaccess            ; test access bits in CX
  1745.  
  1746.         push ds                         ; swap DS and ES, target and source
  1747.         push es
  1748.         pop ds
  1749.         pop es
  1750.  
  1751.         add edi,ebx                     ; adjust EDI to descriptor in GDT
  1752.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1753.         lods dword ptr ds:[esi]
  1754.         or eax,100000h                  ; set descriptor AVL bit
  1755.         stos dword ptr es:[edi]
  1756.  
  1757.         jmp int31ok                     ; return ok
  1758.  
  1759. ;─────────────────────────────────────────────────────────────────────────────
  1760. int31000e:                              ; get multiple descriptors
  1761.         mov ax,000bh                    ; function 000bh, get descriptor
  1762.  
  1763. ;-----------------------------------------------------------------------------
  1764. int31000ef:                             ; common to funcions 000eh and 000fh
  1765.         or cx,cx                        ; if CX = 0, return ok immediately
  1766.         jz int31ok
  1767.  
  1768.         mov dx,cx                       ; DX = number of descriptors
  1769.         xor cx,cx                       ; CX = successful counter
  1770. @@int31000efl0:
  1771.         mov bx,es:[edi]                 ; BX = selector to get
  1772.         add edi,2
  1773.  
  1774.         int 31h                         ; get/set descriptor
  1775.         jc int31failcx                  ; if error, fail with AX and CX
  1776.  
  1777.         add edi,8                       ; increment descriptor ptr
  1778.         inc cx                          ; increment successful copy counter
  1779.         dec dx                          ; decrement loop counter
  1780.         jnz @@int31000efl0              ; if more descriptors to go, loop
  1781.  
  1782.         jmp int31ok                     ; return ok
  1783.  
  1784. ;─────────────────────────────────────────────────────────────────────────────
  1785. int31000f:                              ; set multiple descriptors
  1786.         mov ax,000ch                    ; function 000ch, set descriptor
  1787.  
  1788.         jmp int31000ef                  ; go to common function
  1789.  
  1790. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1791. ; INTERRUPT FUNCTIONS
  1792. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1793.  
  1794. ;─────────────────────────────────────────────────────────────────────────────
  1795. int310200:                              ; get real mode interrupt vector
  1796.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1797.         mov dx,ds:[ebx*4]               ; load real mode vector offset
  1798.         mov cx,ds:[ebx*4+2]             ; load real mode vector segment
  1799.  
  1800.         jmp int31okdx                   ; return ok, with AX, CX, DX
  1801.  
  1802. ;─────────────────────────────────────────────────────────────────────────────
  1803. int310201:                              ; set real mode interrupt vector
  1804.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1805.         mov ds:[ebx*4],dx               ; set real mode vector offset
  1806.         mov ds:[ebx*4+2],cx             ; set real mode vector segment
  1807.  
  1808.         jmp int31ok                     ; return ok
  1809.  
  1810. ;─────────────────────────────────────────────────────────────────────────────
  1811. int310204:                              ; get protected mode interrupt vector
  1812.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1813.         shl ebx,3                       ; adjust for location in IDT
  1814.         add ebx,cs:idtbase              ; add base of IDT
  1815.  
  1816.         mov edx,dword ptr ds:[ebx+4]    ; get high word of offset
  1817.         mov dx,word ptr ds:[ebx]        ; get low word of offset
  1818.         mov cx,word ptr ds:[ebx+2]      ; get selector
  1819.  
  1820.         jmp int31okdx                   ; return ok, with AX, CX, DX
  1821.  
  1822. ;─────────────────────────────────────────────────────────────────────────────
  1823. int310205:                              ; set protected mode interrupt vector
  1824.         xchg bx,cx                      ; swap int number with int selector
  1825.         call int31testsel               ; test for valid selector BX
  1826.  
  1827.         movzx ecx,cl                    ; ECX = CL (interrupt number)
  1828.         shl ecx,3                       ; adjust for location in IDT
  1829.         add ecx,cs:idtbase              ; add base of IDT
  1830.  
  1831.         mov word ptr ds:[ecx],dx        ; set low word of offset
  1832.         shr edx,16
  1833.         mov word ptr ds:[ecx+6],dx      ; set high word of offset
  1834.         mov word ptr ds:[ecx+2],bx      ; set selector
  1835.  
  1836.         jmp int31ok                     ; return ok
  1837.  
  1838. ;─────────────────────────────────────────────────────────────────────────────
  1839. int310900:                              ; get and disable interrupt state
  1840.         add esp,26h                     ; adjust stack
  1841.         pop ds                          ; restore DS
  1842.  
  1843.         btc word ptr [esp+8],9          ; test and clear IF bit in EFLAGS
  1844.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1845.  
  1846.         jmp int31oknopop                ; return ok, dont pop registers
  1847.  
  1848. ;─────────────────────────────────────────────────────────────────────────────
  1849. int310901:                              ; get and enable interrupt state
  1850.         add esp,26h                     ; adjust stack
  1851.         pop ds                          ; restore DS
  1852.  
  1853.         bts word ptr [esp+8],9          ; test and set IF bit in EFLAGS
  1854.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1855.  
  1856.         jmp int31oknopop                ; return ok, dont pop registers
  1857.  
  1858. ;─────────────────────────────────────────────────────────────────────────────
  1859. int310902:                              ; get interrupt state
  1860.         add esp,26h                     ; adjust stack
  1861.         pop ds                          ; restore DS
  1862.  
  1863.         bt word ptr [esp+8],9           ; just test IF bit in EFLAGS
  1864.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1865.  
  1866.         jmp int31oknopop                ; return ok, dont pop registers
  1867.  
  1868. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1869. ; REAL/PROTECTED MODE TRANSLATION FUNCTIONS
  1870. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1871.  
  1872. ;─────────────────────────────────────────────────────────────────────────────
  1873. int310300:                              ; simulate real mode interrupt
  1874.         movzx ebx,bl                    ; get real mode INT CS:IP
  1875.         mov ebp,dword ptr ds:[ebx*4]
  1876.  
  1877. ;-----------------------------------------------------------------------------
  1878. int31030012:                            ; common to 0300h, 0301h, and 0302h
  1879.         mov esi,cs:codebase             ; ESI = offset of PMODE_TEXT from 0
  1880.  
  1881.         movzx ebx,word ptr es:[edi+2eh] ; EBX = SP from register structure
  1882.         movzx edx,word ptr es:[edi+30h] ; EDX = SS from register structure
  1883.  
  1884.         mov ax,bx                       ; check if caller provided stack
  1885.         or ax,dx
  1886.         jnz short @@int31030012f3       ; if yes, go on to set stack
  1887.  
  1888.         mov dx,cs:rmstacktop            ; DX = SS for real mode redirection
  1889.         mov bx,cs:_pm_rmstacklen        ; get size of real mode stack
  1890.         sub dx,bx                       ; adjust DX to next stack location
  1891.  
  1892.         cmp dx,cs:rmstackbase           ; exceeded real mode stack space?
  1893.         jb int31fail8012                ; if yes, error 8012h
  1894.  
  1895.         mov ds:rmstacktop[esi],dx       ; update ptr for possible reenterancy
  1896.         shl bx,4                        ; adjust BX from paragraphs to bytes
  1897.  
  1898. @@int31030012f3:
  1899.         lea edi,[edx*4]                 ; EDI -> top of real mode stack
  1900.         lea edi,[edi*4+ebx]
  1901.  
  1902.         lea ax,[bx-8]                   ; AX = top of stack parms
  1903.         xchg ax,ds:rmstackparmtop[esi]  ; preserve and set new top of stack
  1904.         push ax                         ;  parms for possible reenterancy
  1905.  
  1906.         movzx ax,byte ptr [esp+28]      ; AX = AL of original INT 31h call
  1907.         and al,1                        ; if function 0301h, AL=0, else, AL=2
  1908.         xor al,1
  1909.         shl al,1
  1910.         sub bx,ax                       ; adjust BX for possible FLAGS
  1911.  
  1912.         movzx eax,cx                    ; EAX = length of stack parms
  1913.         shl eax,1
  1914.         sub bx,36h                      ; adjust real mode SP for needed vars
  1915.         sub bx,ax                       ; adjust real mode SP for stack parms
  1916.  
  1917.         mov ds:[edi-2],ss               ; store SS:ESP on real mode stack
  1918.         mov ds:[edi-6],esp
  1919.         mov ds:[edi-8],es               ; store ES on real mode stack
  1920.  
  1921.         push ds                         ; swap DS and ES
  1922.         push es
  1923.         pop ds
  1924.         pop es
  1925.  
  1926.         std                             ; string copy backwards
  1927.  
  1928.         sub edi,10                      ; copy stack parms from protected mode
  1929.         movzx ecx,cx                    ;  stack to real mode stack
  1930.         lea esi,[esp+ecx*2+36h-2]
  1931.         rep movs word ptr es:[edi],word ptr ss:[esi]
  1932.  
  1933.         mov esi,[esp+2]                 ; ESI = offset of structure from stack
  1934.         mov ax,[esi+20h]                ; AX = FLAGS from register structure
  1935.  
  1936.         mov es:[edi],ax                 ; store data for real mode return IRET
  1937.  
  1938.         cmp byte ptr [esp+30],1         ; check AL on stack for function code
  1939.         je short @@int31030012f4        ; if function 0301h, go on
  1940.  
  1941.         and ah,0fch                     ; 0300h or 0302h, clear IF and TF flag
  1942.  
  1943. @@int31030012f4:
  1944.         cld                             ; string copy forward
  1945.         lea edi,[edx*4]                 ; EDI -> bottom of stack
  1946.         lea edi,[edi*4+ebx]
  1947.  
  1948.         mov ecx,8                       ; copy general regs to real mode stack
  1949.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  1950.  
  1951.         add esi,6                       ; copy FS and GS to real mode stack
  1952.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1953.  
  1954.         mov word ptr es:[edi+8],PMODE_TEXT      ; return address from call
  1955.         mov word ptr es:[edi+6],off @@int31030012f1
  1956.  
  1957.         mov es:[edi+4],ax               ; store FLAGS for real mode IRET maybe
  1958.         mov dword ptr es:[edi],ebp      ; put call address to real mode stack
  1959.  
  1960.         mov ax,[esi-6]                  ; real mode DS from register structure
  1961.         mov cx,[esi-8]                  ; real mode ES from register structure
  1962.  
  1963.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1964.         mov di,off @@int31030012f0
  1965.  
  1966.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1967.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1968.  
  1969. @@int31030012f0:                        ; real mode INT, FAR, or IRET call
  1970.         popad                           ; load regs with call values
  1971.         pop fs gs
  1972.  
  1973.         iret                            ; go to call address
  1974.  
  1975. @@int31030012f1:
  1976.         mov sp,cs:rmstackparmtop        ; remove stack parameters
  1977.  
  1978.         push gs fs ds es                ; store registers on stack
  1979.         pushf                           ; store flags on stack
  1980.         pushad
  1981.         cli
  1982.  
  1983.         mov ax,ss                       ; EAX = linear ptr to SS
  1984.         movzx eax,ax
  1985.         shl eax,4
  1986.         movzx ebp,sp                    ; EBP = SP
  1987.  
  1988.         mov cx,[bp+2ah]                 ; get protected mode ES from stack
  1989.         mov ebx,[bp+2ch]                ; get protected mode SS:ESP from stack
  1990.         mov dx,[bp+30h]
  1991.  
  1992.         add ebp,eax                     ; EBP -> stored regs on stack
  1993.  
  1994.         mov ax,SELZERO                  ; DS selector value for protected mode
  1995.         mov si,SELCODE                  ; target CS:EIP in protected mode
  1996.         mov edi,off @@int31030012f2
  1997.  
  1998.         jmp cs:rmtopmswrout             ; go back to protected mode
  1999.  
  2000. @@int31030012f2:
  2001.         mov edi,cs:codebase             ; restore old stack parameter length
  2002.         pop ds:rmstackparmtop[edi]
  2003.  
  2004.         mov edi,[esp]                   ; get structure offset from stack
  2005.         mov esi,ebp                     ; copy return regs from real mode
  2006.         mov ecx,15h                     ;  stack to register structure
  2007.         cld
  2008.         rep movs word ptr es:[edi],word ptr ds:[esi]
  2009.  
  2010.         cmp dword ptr es:[edi+4],0      ; stack provided by caller?
  2011.         jne int31ok                     ; if yes, done now
  2012.  
  2013.         mov edi,cs:codebase             ; restore top of real mode stack
  2014.         mov ax,cs:_pm_rmstacklen
  2015.         add ds:rmstacktop[edi],ax
  2016.  
  2017.         jmp int31ok                     ; return ok
  2018.  
  2019. ;─────────────────────────────────────────────────────────────────────────────
  2020. int310301:                              ; call real mode FAR procedure
  2021.                                         ; same start as function 0302h
  2022. ;─────────────────────────────────────────────────────────────────────────────
  2023. int310302:                              ; call real mode IRET procedure
  2024.         mov ebp,dword ptr es:[edi+2ah]  ; get target CS:IP from structure
  2025.         jmp int31030012                 ; go to common code
  2026.  
  2027. ;─────────────────────────────────────────────────────────────────────────────
  2028. int310303:                              ; allocate real mode callback address
  2029.         mov bl,cs:_pm_callbacks         ; CL = total number of callbacks
  2030.         or bl,bl                        ; are there any?
  2031.         jz int31fail8015                ; if no, error 8015h
  2032.  
  2033.         mov edx,cs:callbackbase         ; EDX -> base of callbacks
  2034.         mov ecx,edx                     ; for later use
  2035.  
  2036. @@int310303l0:
  2037.         cmp word ptr [edx+3],0          ; is this callback free?
  2038.         jz short @@int310303f0          ; if yes, allocate
  2039.  
  2040.         add edx,25                      ; increment ptr to callback
  2041.         dec bl                          ; decrement loop counter
  2042.         jnz @@int310303l0               ; if more callbacks to check, loop
  2043.  
  2044.         jmp int31fail8015               ; no free callback, error 8015h
  2045.  
  2046. @@int310303f0:
  2047.         mov bx,[esp+38]                 ; BX = caller DS from stack
  2048.         mov [edx+3],bx                  ; store callback parms in callback
  2049.         mov [edx+7],esi
  2050.         mov [edx+12],es
  2051.         mov [edx+16],edi
  2052.  
  2053.         sub edx,ecx                     ; DX = offset of callback
  2054.         shr ecx,4                       ; CX = segment of callback
  2055.  
  2056.         jmp int31okdx                   ; return ok, with DX, CX, AX
  2057.  
  2058. ;─────────────────────────────────────────────────────────────────────────────
  2059. int310304:                              ; free real mode callback address
  2060.         cmp cx,cs:callbackseg           ; valid callback segment?
  2061.         jne int31fail8024               ; if no, error 8024h
  2062.  
  2063.         movzx ebx,dx                    ; EBX = offset of callback
  2064.  
  2065.         xor ax,ax                       ; check if valid offset
  2066.         xchg dx,ax
  2067.         mov cx,25
  2068.         div cx
  2069.  
  2070.         or dx,dx                        ; is there a remainder
  2071.         jnz int31fail8024               ; if yes, not valid, error 8024h
  2072.  
  2073.         or ah,ah                        ; callback index too big?
  2074.         jnz int31fail8024               ; if yes, not valid, error 8024h
  2075.  
  2076.         cmp al,cs:_pm_callbacks         ; callback index out of range?
  2077.         jae int31fail8024               ; if yes, not valid, error 8024h
  2078.  
  2079.         add ebx,cs:callbackbase         ; EBX -> callback
  2080.         mov word ptr [ebx+3],0          ; set callback as free
  2081.  
  2082.         jmp int31ok                     ; return ok
  2083.  
  2084. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2085. ; MISC FUNCTIONS
  2086. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2087.  
  2088. ;─────────────────────────────────────────────────────────────────────────────
  2089. int310305:                              ; get state save/restore addresses
  2090.         add esp,26h                     ; adjust stack
  2091.         pop ds                          ; restore DS
  2092.  
  2093.         xor ax,ax                       ; size needed is none
  2094.         mov bx,PMODE_TEXT               ; real mode seg of same RETF
  2095.         mov cx,off vxr_saverestorerm    ; same offset of 16bit RETF
  2096.         mov si,cs                       ; selector of routine is this one
  2097.         mov edi,off vxr_saverestorepm   ; offset of simple 32bit RETF
  2098.  
  2099.         jmp int31oknopop                ; return ok, dont pop registers
  2100.  
  2101. ;─────────────────────────────────────────────────────────────────────────────
  2102. int310306:                              ; get raw mode switch addresses
  2103.         add esp,26h                     ; adjust stack
  2104.         pop ds                          ; restore DS
  2105.  
  2106.         mov si,cs                       ; selector of pmtorm rout is this one
  2107.         mov edi,cs:pmtormswrout         ; offset in this seg of rout
  2108.         mov bx,PMODE_TEXT               ; real mode seg of rmtopm rout
  2109.         mov cx,cs:rmtopmswrout          ; offset of rout in real mode
  2110.  
  2111.         jmp int31oknopop                ; return ok, dont pop registers
  2112.  
  2113. ;─────────────────────────────────────────────────────────────────────────────
  2114. int310400:                              ; get version
  2115.         add esp,26h                     ; adjust stack
  2116.         pop ds                          ; restore DS
  2117.  
  2118.         mov ax,100h                     ; return version 1.0
  2119.         mov bx,3                        ; capabilities
  2120.         mov cl,cs:processortype         ; processor type
  2121.         mov dx,word ptr cs:picslave     ; master and slave PIC values
  2122.  
  2123.         jmp int31oknopop                ; return ok, dont pop registers
  2124.  
  2125. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2126. ; VCPI EXTENDED MEMORY FUNCTIONS
  2127. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2128.  
  2129. ;-----------------------------------------------------------------------------
  2130. int310500vsiditoesi:                    ; convert handle SI:DI to ptr ESI
  2131.         pop bp                          ; pop return address
  2132.  
  2133.         test di,3                       ; is handle (ptr) aligned on dword?
  2134.         jnz int31fail8023               ; if no, error 8023h
  2135.  
  2136.         shl esi,16                      ; ESI = SI:DI
  2137.         mov si,di
  2138.  
  2139.         cmp esi,cs:pagetablebase        ; handle too low?
  2140.         jb int31fail8023                ; if yes, error 8023h
  2141.  
  2142.         cmp esi,cs:pagetabletop         ; handle too high?
  2143.         jae int31fail8023               ; if yes, error 8023h
  2144.  
  2145.         test byte ptr [esi+1],2         ; is page first in allocated block?
  2146.         jz int31fail8023                ; if no, error 8023h
  2147.  
  2148.         jmp bp                          ; return ok
  2149.  
  2150. ;-----------------------------------------------------------------------------
  2151. int310500vbxcxtoebx:                    ; convert BX:CX bytes to EBX pages
  2152.         pop bp                          ; pop return address
  2153.  
  2154.         shl ebx,16                      ; EBX = BX:CX
  2155.         mov bx,cx
  2156.  
  2157.         or ebx,ebx                      ; check for invalid value
  2158.         jz int31fail8021                ; if invalid value, error 8021h
  2159.  
  2160.         add ebx,0fffh                   ; convert EBX to page count
  2161.         shr ebx,12
  2162.  
  2163.         jmp bp                          ; return ok
  2164.  
  2165. ;-----------------------------------------------------------------------------
  2166. int310500vpmalloc:                      ; allocate physical memory block
  2167.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2168.         xor ebp,ebp                     ; EBP = running allocated page count
  2169.  
  2170. @@int310500vpmallocl0:
  2171.         mov ax,0de04h                   ; VCPI allocate a page
  2172.         call fword ptr cs:vcpi_calleip
  2173.  
  2174.         or ah,ah                        ; got a page?
  2175.     jz short @@int310500vpmallocl0f0; if yes, go on
  2176.  
  2177.     cmp ebp,1            ; allocated any pages?
  2178.     jc short @@int310500vpmallocdone; if no, fail immediately
  2179.  
  2180.     or byte ptr [edi-3],4        ; set last allocated page as last
  2181.  
  2182.     call int310500vfree        ; free what was allocated
  2183.  
  2184.     stc                ; carry set, failed
  2185.     jmp short @@int310500vpmallocdone    ; go to done
  2186.  
  2187. @@int310500vpmallocl0f0:
  2188.         or dl,7                         ; set page as user/writeable/present
  2189.         mov [edi],edx                   ; store page in page table
  2190.     add edi,4            ; increment page table ptr
  2191.  
  2192.     inc ebp             ; increment allocated page count
  2193.     cmp ebp,ebx            ; allocated all needed pages?
  2194.     jb @@int310500vpmallocl0    ; if no, loop
  2195.  
  2196.         or byte ptr [esi+1],2           ; set first allocated page as first
  2197.         or byte ptr [edi-3],4           ; set last allocated page as last
  2198.         clc                             ; carry clear, success
  2199.  
  2200. @@int310500vpmallocdone:
  2201.         mov eax,ebp                     ; EAX = number of pages allocated
  2202.     ret                ; return
  2203.  
  2204. ;-----------------------------------------------------------------------------
  2205. int310500vlmalloc:                      ; check for linear memory block
  2206.         mov edi,cs:pagetablebase        ; EDI = search ptr in page table
  2207.  
  2208.         mov ecx,cs:pagetabletop         ; ECX = count of pages to search
  2209.         sub ecx,edi
  2210.         shr ecx,2
  2211.  
  2212.         xor edx,edx                     ; EDX = largest linear block found
  2213.         xor eax,eax                     ; EAX = search unit, free entry (0)
  2214.  
  2215.         push ebx                        ; preserve EBX, memory requested
  2216.  
  2217. @@int310500vlmallocl0:
  2218.         jecxz short @@int310500vlmallocdone     ; if no more entries, done
  2219.  
  2220.         repne scas dword ptr es:[edi]   ; search for first next free entry
  2221.         jne short @@int310500vlmallocdone       ; if no more free, go on
  2222.  
  2223.         mov ebp,ecx                     ; EBP = current count
  2224.         lea ebx,[edi-4]                 ; EBX = start of free block
  2225.  
  2226.         repe scas dword ptr es:[edi]    ; search for end of free linear block
  2227.         jne short @@int310500vlmallocl0f0; if previous entry not free, go on
  2228.  
  2229.         inc ebp                         ; previous entry free, extra one
  2230.  
  2231. @@int310500vlmallocl0f0:
  2232.         sub ebp,ecx                     ; EBP = number of free pages in block
  2233.  
  2234.         cmp ebp,edx                     ; new block larger than last largest?
  2235.         jb @@int310500vlmallocl0        ; if no, loop
  2236.  
  2237.         mov esi,ebx                     ; ESI = ptr to largest block found
  2238.         mov edx,ebp                     ; size of new largest block found
  2239.  
  2240.         cmp ebp,[esp]                   ; block sufficient for memory request?
  2241.         jb @@int310500vlmallocl0        ; if no, loop
  2242.  
  2243. @@int310500vlmallocdone:
  2244.         pop ebx                         ; restore EBX, memory requested
  2245.         ret                             ; return
  2246.  
  2247. ;-----------------------------------------------------------------------------
  2248. int310500vmalloc:                       ; allocate linear+physical mem block
  2249.         call int310500vlmalloc          ; try to allocate linear memory block
  2250.  
  2251.         cmp edx,1                       ; found ANY free linear area?
  2252.         jc short @@int310500vmallocdone ; if no, done
  2253.  
  2254.         cmp edx,ebx                     ; linear block enough for request?
  2255.         jb short @@int310500vmallocf0   ; if no, go to physical memory check
  2256.  
  2257.         call int310500vpmalloc          ; try to allocate physical mem
  2258.  
  2259.         mov cl,1                        ; error is not enough physical memory
  2260.         jmp short @@int310500vmallocdone; go to done
  2261.  
  2262. @@int310500vmallocf0:
  2263.         mov ebx,edx                     ; only linear block size physical mem
  2264.  
  2265.         call int310500vpmalloc          ; try to allocate physical memory
  2266.         jc short @@int310500vmallocfaillinear   ; if failed, done
  2267.  
  2268.         call int310500vfree             ; success, so must free block
  2269.  
  2270.         mov eax,ebx                     ; can allocate this much total memory
  2271.         stc                             ; carry set, failed
  2272.  
  2273. @@int310500vmallocfaillinear:
  2274.         mov cl,0                        ; error is not enough linear memory
  2275.  
  2276. @@int310500vmallocdone:
  2277.         ret                             ; return
  2278.  
  2279. ;-----------------------------------------------------------------------------
  2280. int310500vfree:                         ; free linear+physical memory block
  2281.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2282.  
  2283. @@int310500vfreel0:
  2284.         xor ecx,ecx                     ; new page table entry is free (0)
  2285.     xchg ecx,[edi]            ; swap ECX with page table entry
  2286.     add edi,4            ; increment page table ptr
  2287.  
  2288.         mov edx,ecx                     ; EDX = page table entry
  2289.         and dx,0f000h                   ; mask off low 12 bits
  2290.  
  2291.         mov ax,0de05h                   ; VCPI free a page
  2292.         call fword ptr cs:vcpi_calleip
  2293.  
  2294.         test ch,4                       ; last page of block?
  2295.         jz @@int310500vfreel0           ; if no, loop
  2296.  
  2297.         ret                             ; return
  2298.  
  2299. ;─────────────────────────────────────────────────────────────────────────────
  2300. int310500v:                             ; VCPI get free memory information
  2301.         push ds                         ; ES = DS for VCPI malloc functions
  2302.         pop es
  2303.  
  2304.         mov ebx,0ffffffffh              ; try to allocate an impossible amount
  2305.         call int310500vmalloc
  2306.  
  2307.         shl eax,12                      ; returned EAX is highest possible
  2308.  
  2309.         jmp int310500xsetbuf            ; put memory information in buffer
  2310.  
  2311. ;─────────────────────────────────────────────────────────────────────────────
  2312. int310501v:                             ; VCPI allocate memory block
  2313.         push ds                         ; ES = DS for VCPI malloc functions
  2314.         pop es
  2315.  
  2316.         call int310500vbxcxtoebx        ; convert BX:CX bytes to EBX pages
  2317.  
  2318.         call int310500vmalloc           ; try to allocate requested amount
  2319.         jnc short int310501vaddxnhandle ; if successful, go to done
  2320.  
  2321.         or cl,cl                        ; error is not enough linear memory?
  2322.         jz int31fail8012                ; if yes, error 8013h
  2323.         jmp int31fail8013               ; error is physical, error 8013h
  2324.  
  2325. int310501vaddxnhandle:
  2326.         mov ecx,esi                     ; figure address of block from handle
  2327.         sub ecx,cs:pagetablebase
  2328.         shl ecx,10
  2329.         shld ebx,ecx,16
  2330.  
  2331.         mov di,si                       ; SI:DI = ESI, handle
  2332.         shr esi,16
  2333.  
  2334.         mov eax,cs:vcpi_cr3             ; reload CR3 to clear TLB
  2335.         mov cr3,eax
  2336.  
  2337.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2338.  
  2339. ;─────────────────────────────────────────────────────────────────────────────
  2340. int310502v:                             ; VCPI free memory block
  2341.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2342.  
  2343.         call int310500vfree             ; free memory block
  2344.  
  2345.         mov eax,cs:vcpi_cr3             ; reload CR3 to clear TLB
  2346.         mov cr3,eax
  2347.  
  2348.         jmp int31ok                     ; return ok
  2349.  
  2350. ;─────────────────────────────────────────────────────────────────────────────
  2351. int310503v:                             ; VCPI resize memory block
  2352.         push ds                         ; ES = DS for VCPI malloc functions
  2353.         pop es
  2354.  
  2355.         call int310500vbxcxtoebx        ; convert BX:CX bytes to EBX pages
  2356.  
  2357.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2358.  
  2359.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2360.         xor ebp,ebp                     ; EBP = running block size in pages
  2361.  
  2362. @@int310503vl0:
  2363.         add edi,4                       ; increment page table ptr
  2364.         inc ebp                         ; increment block size
  2365.  
  2366.         test byte ptr [edi-3],4         ; last page of block?
  2367.         jz @@int310503vl0               ; if no, loop
  2368.  
  2369.         sub ebx,ebp                     ; EBX = change in block size
  2370.         jz int310501vaddxnhandle        ; if no change, done
  2371.  
  2372.         jc @@int310503vf0               ; if block made smaller, just free top
  2373.  
  2374.         mov ecx,cs:pagetabletop         ; ECX = count of pages to search
  2375.         sub ecx,edi
  2376.         shr ecx,2
  2377.  
  2378.         mov edx,ecx                     ; EDX = current count
  2379.         xor eax,eax                     ; EAX = search unit, free entry (0)
  2380.  
  2381.         jecxz short @@int310503vf3      ; if no entries above, try below
  2382.  
  2383.         repe scas dword ptr es:[edi]    ; check for free entries above block
  2384.         je short @@int310503vf2         ; if previous entry free, go on
  2385.  
  2386.         dec edx                         ; previous entry not free, minus one
  2387.  
  2388. @@int310503vf2:
  2389.         sub edx,ecx                     ; EDX = number of free pages in block
  2390.  
  2391.         cmp edx,ebx                     ; enough linear memory?
  2392.         jb short @@int310503vf3         ; if no, try below in linear memory
  2393.  
  2394.         push esi                        ; preserve start of block
  2395.         lea esi,[esi+ebp*4]             ; ESI -> start of new block for alloc
  2396.  
  2397.         call int310500vpmalloc          ; try to allocate physical memory
  2398.         mov edi,esi                     ; EDI -> start of new block
  2399.         pop esi                         ; restore start of old block
  2400.         jc int31fail8013                ; if alloc failed, error 8013h
  2401.  
  2402.         and byte ptr [edi-3],0fbh       ; clear last bit in old block end
  2403.         and byte ptr [edi+1],0fdh       ; clear first bit in new block start
  2404.  
  2405.         jmp int310501vaddxnhandle       ; go to done
  2406.  
  2407. @@int310503vf3:
  2408.         mov ecx,esi                     ; ECX = count of pages to search up
  2409.         sub ecx,cs:pagetablebase
  2410.         shr ecx,2
  2411.  
  2412.         or ecx,ecx                      ; any linear memory below?
  2413.         jz @@int310503vf1               ; if no, try to allocate
  2414.  
  2415.         push ebp                        ; preserve size of original block
  2416.  
  2417.         lea edi,[esi-4]                 ; EDI = ESI, ptr to linear block start
  2418.         mov ebp,ecx                     ; EBP = current count
  2419.  
  2420.         std                             ; search is up
  2421.         repe scas dword ptr es:[edi]    ; check for free entries after block
  2422.         cld
  2423.         je short @@int310503vf4         ; if previous entry free, go on
  2424.  
  2425.         dec ebp                         ; previous entry not free, minus one
  2426.  
  2427. @@int310503vf4:
  2428.         sub ebp,ecx                     ; EBP = number of free pages in block
  2429.         lea eax,[ebp+edx]               ; free size below + free size above
  2430.  
  2431.         pop ebp                         ; restore original block size
  2432.  
  2433.         cmp eax,ebx                     ; enough linear memory?
  2434.         jb @@int310503vf1               ; if no, try to allocate
  2435.  
  2436.         push esi                        ; preserve original block address
  2437.  
  2438.         sub ebx,edx                     ; EBX = number of pages needed below
  2439.         lea eax,[ebx*4]                 ; get base of block below
  2440.         sub esi,eax
  2441.  
  2442.         push edx ebp                    ; preserve some vars
  2443.         call int310500vpmalloc          ; try to allocate physical memory
  2444.         pop ebp edx                     ; restore some vars
  2445.  
  2446.         mov edi,esi                     ; EDI -> base of block below
  2447.         pop esi                         ; restore base of original block
  2448.         jc int31fail8013                ; if alloc failed, error 8013h
  2449.  
  2450.         or edx,edx                      ; any pages needed above?
  2451.         jz short @@int310503vf6         ; if no, go on
  2452.  
  2453.         push esi edi ebp                ; preserve some vars
  2454.  
  2455.         mov ebx,edx                     ; EBX = size of block below
  2456.         lea esi,[esi+ebp*4]             ; ESI -> start of block above
  2457.  
  2458.         call int310500vpmalloc          ; try to allocate physical memory
  2459.         pop ebp edi esi                 ; restore some vars
  2460.         jnc short @@int310503vf5        ; if allocated ok, go on
  2461.  
  2462.         mov esi,edi                     ; ESI -> allocated block below
  2463.         call int310500vfree             ; free allocated block below
  2464.  
  2465.         jmp int31fail8013               ; fail, error 8013h
  2466.  
  2467. @@int310503vf5:
  2468.         and byte ptr [esi-3],0fbh       ; clear last bit in below block end
  2469.         and byte ptr [esi+ebp*4+1],0fdh ; clear first bit in above block start
  2470.  
  2471. @@int310503vf6:
  2472.         and byte ptr [edi+1],0fdh       ; clear first bit in below block start
  2473.         and byte ptr [esi+ebp*4-3],0fbh ; clear last bit in old block end
  2474.  
  2475.         push edi                        ; preserve new block start
  2476.  
  2477.         mov edx,edi                     ; EDX = base of move area
  2478.         lea ebx,[esi-4]                 ; EBX = current location in move area
  2479.  
  2480. @@int310503vl1:
  2481.         mov edi,ebx                     ; set up to shift up a page
  2482.         mov esi,ebx
  2483.         mov ecx,ebp
  2484.  
  2485.         lods dword ptr ds:[esi]         ; shift old pages a page down in table
  2486.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  2487.         stos dword ptr es:[edi]
  2488.  
  2489.         sub ebx,4                       ; decrement to next page to shift
  2490.         cmp ebx,edx                     ; more pages to shift?
  2491.         jae @@int310503vl1              ; if yes, loop
  2492.  
  2493.         pop esi                         ; restore new block start address
  2494.  
  2495.         jmp int310501vaddxnhandle       ; go to done
  2496.  
  2497. @@int310503vf1:
  2498.         add ebx,ebp                     ; restore EBX as requested size
  2499.  
  2500.         push esi ebp                    ; preserve some vars
  2501.         call int310500vlmalloc          ; check for linear memory block
  2502.         pop ebp edi                     ; restore some vars
  2503.  
  2504.         cmp edx,ebx                     ; enough linear memory?
  2505.         jb int31fail8012                ; if no, error 8012h
  2506.  
  2507.         sub ebx,ebp                     ; EBX = extra pages needed
  2508.         push esi                        ; preserve for later copy
  2509.         lea esi,[esi+ebp*4]             ; ESI -> start of extra space needed
  2510.  
  2511.         push edi ebp                    ; preserve some vars
  2512.         call int310500vpmalloc          ; try to allocate physical memory
  2513.         pop ecx esi edi                 ; restore some vars
  2514.         jc int31fail8013                ; if not enough mem, error 8013h
  2515.  
  2516.         push edi esi ecx                ; preserve, new and old block, size
  2517.  
  2518.         rep movs dword ptr es:[edi],dword ptr ds:[esi]  ; copy old block pages
  2519.  
  2520.         and byte ptr [edi-3],0fbh       ; clear last bit in old block end
  2521.         and byte ptr [edi+1],0fdh       ; clear first bit in new block start
  2522.  
  2523.         pop ecx edi                     ; restore to clear old block
  2524.  
  2525.         xor eax,eax                     ; new page table entry is free (0)
  2526.         rep stos dword ptr es:[edi]     ; clear old page table block
  2527.  
  2528.         pop esi                         ; restore new block address
  2529.  
  2530.         jmp int310501vaddxnhandle       ; go to done
  2531.  
  2532. @@int310503vf0:
  2533.         sub edi,4                       ; decrement page table ptr
  2534.  
  2535.         xor edx,edx                     ; new page table entry is free (0)
  2536.         xchg edx,[edi]                  ; swap EDX with page table entry
  2537.         and dx,0f000h                   ; mask off low 12 bits
  2538.  
  2539.         mov ax,0de05h                   ; VCPI free a page
  2540.         call fword ptr cs:vcpi_calleip
  2541.  
  2542.         inc ebx                         ; increment negative change counter
  2543.         jnz @@int310503vf0              ; if more pages to free, loop
  2544.  
  2545.         or byte ptr [edi-3],4           ; set next page up as last of block
  2546.  
  2547.         jmp int310501vaddxnhandle       ; go to done
  2548.  
  2549. ;─────────────────────────────────────────────────────────────────────────────
  2550. int31050av:                             ; VCPI get memory block size and base
  2551.         shrd ecx,esi,16                 ; figure address of block from handle
  2552.         mov cx,di
  2553.         sub ecx,cs:pagetablebase
  2554.         shl ecx,10
  2555.         shld ebx,ecx,16
  2556.  
  2557.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2558.  
  2559.         xor edi,edi                     ; EDI = running page count
  2560.  
  2561. @@int31050avl0:
  2562.         inc edi                         ; increment page count
  2563.  
  2564.         lods dword ptr ds:[esi]         ; EAX = page table entry
  2565.         test ah,4                       ; is this the last page of the block?
  2566.         jz @@int31050avl0               ; if no, loop
  2567.  
  2568.         shl edi,12                      ; convert EDI pages to bytes
  2569.         shld esi,edi,16                 ; SI:DI = EDI, size in bytes
  2570.  
  2571.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2572.  
  2573. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2574. ; XMS EXTENDED MEMORY FUNCTIONS
  2575. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2576.  
  2577. ;-----------------------------------------------------------------------------
  2578. int310500xsetbuf:
  2579.         mov es,[esp+24h]                ; get ES:EDI buffer ptr from stack
  2580.         mov edi,[esp]
  2581.  
  2582.         stos dword ptr es:[edi]         ; store block size in output buffer
  2583.         mov ecx,0bh                     ; fill rest of buffer with 0ffffffffh
  2584.         mov eax,0ffffffffh
  2585.         rep stos dword ptr es:[edi]
  2586.  
  2587.         jmp int31ok                     ; return ok
  2588.  
  2589. ;-----------------------------------------------------------------------------
  2590. int310500xcallxms:                      ; make a all to real mode XMS driver
  2591.         pop bp                          ; pop return address
  2592.         sub esp,32h                     ; stack space for register structure
  2593.  
  2594.         mov [esp+1ch],ax                ; put AX in register structure
  2595.         mov [esp+10h],bx                ; put BX in register structure
  2596.         mov [esp+18h],cx                ; put CX in register structure
  2597.         mov [esp+14h],dx                ; put DX in register structure
  2598.  
  2599.         mov word ptr [esp+20h],0        ; zero FLAGS in register structure
  2600.         mov dword ptr [esp+2eh],0       ; zero SS:SP in register structure
  2601.         mov eax,dword ptr cs:xms_callip ; put XMS driver address in CS:IP in
  2602.         mov [esp+2ah],eax               ;  regis]er structure
  2603.  
  2604.         push ss                         ; ES:EDI -> register structure
  2605.         pop es
  2606.         mov edi,esp
  2607.  
  2608.         xor cx,cx                       ; copy 0 words as stack parameters
  2609.         xor bh,bh                       ; doesnt really need to be here
  2610.         mov ax,301h                     ; call real mode FAR procedure
  2611.         int 31h
  2612.  
  2613.         mov ax,[esp+1ch]                ; get AX from register structure
  2614.         mov bx,[esp+10h]                ; get BX from register structure
  2615.         mov cx,[esp+18h]                ; get CX from register structure
  2616.         mov dx,[esp+14h]                ; get DX from register structure
  2617.  
  2618.         lea esp,[esp+32h]               ; adjust ESP without changing FLAGS
  2619.         jc int31fail8010                ; if INT 31h failed, error 8010h
  2620.  
  2621.         jmp bp                          ; return ok
  2622.  
  2623. ;-----------------------------------------------------------------------------
  2624. int310500xbxcxtodx:                     ; convert BX:CX bytes to DX K
  2625.         pop bp                          ; pop return address
  2626.  
  2627.         mov dx,cx                       ; check for invalid value, BX=CX=0
  2628.         or dx,bx
  2629.         jz int31fail8021                ; if invalid value, error 8021h
  2630.  
  2631.         add cx,1023+15                  ; adjust for size in K and align
  2632.         adc bx,0
  2633.  
  2634.         test bh,0fch                    ; memory request too high
  2635.         jnz int31fail8013               ; if yes, error 8013h
  2636.  
  2637.         shrd cx,bx,10                   ; CX = memory in K
  2638.         mov dx,cx
  2639.  
  2640.         jmp bp                          ; return ok
  2641.  
  2642. ;-----------------------------------------------------------------------------
  2643. int310500xerror:                        ; XMS error, return with DPMI error
  2644.         cmp bl,0a0h                     ; out of memory?
  2645.         je int31fail8013                ; if yes, error 8013h
  2646.  
  2647.         cmp bl,0a1h                     ; handles exhausted?
  2648.         je int31fail8016                ; if yes, error 8016h
  2649.  
  2650.         cmp bl,0a2h                     ; invalid handle?
  2651.         je int31fail8023                ; if yes, error 8023h
  2652.  
  2653.         jmp int31fail8010               ; else, error 8010h
  2654.  
  2655. ;─────────────────────────────────────────────────────────────────────────────
  2656. int310500x:                             ; XMS get free memory information
  2657.         mov ah,8                        ; get largest free memory block in K
  2658.         call int310500xcallxms
  2659.  
  2660.         movzx eax,ax                    ; EAX = free memory in bytes
  2661.         shl eax,10
  2662.  
  2663.         sub eax,15                      ; adjust by extra alignment size
  2664.         jnc int310500xsetbuf            ; if no overflow, put info to buffer
  2665.  
  2666.         xor eax,eax                     ; overflow, so no memory available
  2667.         jmp int310500xsetbuf            ; put memory information in buffer
  2668.  
  2669. ;─────────────────────────────────────────────────────────────────────────────
  2670. int310501x:                             ; XMS allocate memory block
  2671.         call int310500xbxcxtodx         ; convert BX:CX bytes to DX K
  2672.         mov cx,dx                       ; preserve size of block in K
  2673.  
  2674.         mov ah,9                        ; allocate DX K of XMS memory
  2675.         call int310500xcallxms
  2676.         or ax,ax                        ; error?
  2677.         jz int310500xerror              ; if yes, convert XMS error to DPMI
  2678.  
  2679.         mov si,dx                       ; get DPMI handle from XMS handle
  2680.  
  2681. int310501xgotmem:
  2682.         mov ah,0ch                      ; lock memory block
  2683.         call int310500xcallxms
  2684.         or ax,ax                        ; error?
  2685.         jnz short @@int310501xf0        ; if no, go on
  2686.  
  2687.         push bx                         ; yup, preserve error number
  2688.  
  2689.         mov ah,0ah                      ; free block causing lock error
  2690.         call int310500xcallxms
  2691.  
  2692.         pop bx                          ; restore error number
  2693.         jmp int310500xerror             ; XMS error, return with DPMI error
  2694.  
  2695. @@int310501xf0:
  2696.         mov di,cx                       ; low word of DPMI handle is size in K
  2697.  
  2698.         mov cx,bx                       ; XMS linear address to DPMI regs
  2699.         mov bx,dx
  2700.  
  2701.         add cx,0fh                      ; align linear address on paragraph
  2702.         adc bx,0
  2703.         and cl,0f0h
  2704.  
  2705.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2706.  
  2707. ;─────────────────────────────────────────────────────────────────────────────
  2708. int310502x:                             ; XMS free memory block
  2709.         mov dx,si                       ; get XMS handle from DPMI handle
  2710.  
  2711.         mov ah,0dh                      ; unlock memory block
  2712.         call int310500xcallxms
  2713.         or ax,ax                        ; error?
  2714.         jz int310500xerror              ; if XMS error, return with DPMI error
  2715.  
  2716.         mov ah,0ah                      ; free memory block
  2717.         call int310500xcallxms
  2718.         or ax,ax                        ; error?
  2719.         jz int310500xerror              ; if yes, convert XMS error to DPMI
  2720.  
  2721.         jmp int31ok                     ; return ok
  2722.  
  2723. ;─────────────────────────────────────────────────────────────────────────────
  2724. int310503x:                             ; XMS resize memory block
  2725.         call int310500xbxcxtodx         ; convert BX:CX bytes to DX K
  2726.         mov cx,dx                       ; preserve size of block in K
  2727.         mov dx,si                       ; get XMS handle from DPMI handle
  2728.  
  2729.         mov ah,0dh                      ; unlock memory block
  2730.         call int310500xcallxms
  2731.         or ax,ax                        ; error?
  2732.         jz int310500xerror              ; if XMS error, return with DPMI error
  2733.  
  2734.         mov bx,cx                       ; BX = new size in K
  2735.         mov ah,0fh                      ; resize memory block
  2736.         call int310500xcallxms
  2737.         mov dx,si                       ; get XMS handle again
  2738.         or ax,ax                        ; error in resize?
  2739.         jnz int310501xgotmem            ; if no, go to memory block code
  2740.  
  2741.         push bx                         ; yup, preserve error number
  2742.  
  2743.         mov ah,0ch                      ; lock memory block
  2744.         call int310500xcallxms
  2745.  
  2746.         pop bx                          ; restore error number
  2747.         jmp int310500xerror             ; XMS error, return with DPMI error
  2748.  
  2749. ;─────────────────────────────────────────────────────────────────────────────
  2750. int31050ax:                             ; XMS get memory block size and base
  2751.         mov dx,si                       ; get XMS handle from DPMI handle
  2752.         mov si,di                       ; SI = size of block in K
  2753.  
  2754.         mov ah,0dh                      ; unlock memory block
  2755.         call int310500xcallxms
  2756.         or ax,ax                        ; error?
  2757.         jz int310500xerror              ; if XMS error, return with DPMI error
  2758.  
  2759.         mov ah,0ch                      ; lock memory block
  2760.         call int310500xcallxms
  2761.         or ax,ax                        ; error?
  2762.         jz int310500xerror              ; if XMS error, return with DPMI error
  2763.  
  2764.         xor di,di                       ; convert size in K to size in bytes
  2765.         shrd di,si,6
  2766.         shr si,6
  2767.  
  2768.         mov cx,bx                       ; XMS linear address to DPMI regs
  2769.         mov bx,dx
  2770.  
  2771.         mov ax,cx                       ; figure out alignment stub
  2772.         dec ax
  2773.         and ax,0fh
  2774.         xor al,0fh
  2775.  
  2776.         sub di,ax                       ; subtract alignment stub from size
  2777.         sbb si,0
  2778.  
  2779.         add cx,0fh                      ; align linear address on paragraph
  2780.         adc bx,0
  2781.         and cl,0f0h
  2782.  
  2783.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2784.  
  2785. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2786. ; RAW EXTENDED MEMORY FUNCTIONS
  2787. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2788.  
  2789. ;-----------------------------------------------------------------------------
  2790. int310500rnomem:                        ; no free extended memory present
  2791.         xor eax,eax                     ; 0 available extended memory
  2792.         jmp int310500xsetbuf            ; put memory information in buffer
  2793.  
  2794. ;-----------------------------------------------------------------------------
  2795. int310500rbxcxtoebx:                    ; convert BX:CX bytes to EBX bytes
  2796.         pop bp                          ; pop return address
  2797.  
  2798.         shl ebx,16                      ; EBX = BX:CX
  2799.         mov bx,cx
  2800.  
  2801.         or ebx,ebx                      ; check for invalid value
  2802.         jz int31fail8021                ; if invalid value, error 8021h
  2803.  
  2804.         add ebx,0fh                     ; align EBX on paragraph
  2805.         and bl,0f0h
  2806.  
  2807.         jmp bp                          ; return ok
  2808.  
  2809. ;-----------------------------------------------------------------------------
  2810. int310500rfindmcb:                      ; find MCB for handle SI:DI
  2811.         pop bp                          ; pop return address
  2812.  
  2813.         shl esi,16                      ; ESI = handle SI:DI = address of MCB
  2814.         mov si,di
  2815.  
  2816.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2817.  
  2818. @@int310500rfindmcbl0:
  2819.         cmp edi,esi                     ; found MCB?
  2820.         jne short @@int310500rfindmcbl0f0       ; if no, keep looking
  2821.  
  2822.         cmp byte ptr [edi-4],0          ; memory block free?
  2823.         je int31fail8023                ; if yes, error 8023h
  2824.  
  2825.         jmp bp                          ; return ok, found MCB
  2826.  
  2827. @@int310500rfindmcbl0f0:
  2828.         mov edi,[edi-12]                ; EDI -> next memory control block
  2829.         or edi,edi                      ; is there another MCB?
  2830.         jnz @@int310500rfindmcbl0       ; if yes, loop
  2831.  
  2832.         jmp int31fail8023               ; fail, error 8023h
  2833.  
  2834. ;-----------------------------------------------------------------------------
  2835. int310500radjustused:                   ; adjust INT 15h extended memory used
  2836.         mov eax,cs:rawextmemtop         ; EAX -> first memory control block
  2837.  
  2838. @@int310500radjustusedl0:
  2839.         cmp dword ptr [eax-12],0        ; last memory control block?
  2840.         jz short @@int310500radjustusedf0       ; if yes, go to set new used K
  2841.  
  2842.         mov eax,[eax-12]                ; EAX -> next memory control block
  2843.         jmp @@int310500radjustusedl0    ; loop
  2844.  
  2845. @@int310500radjustusedf0:
  2846.         cmp byte ptr [eax-4],0          ; memory block free?
  2847.         je short @@int310500radjustusedf1       ; if no, go on
  2848.  
  2849.         sub eax,[eax-16]                ; used, adjust by size of block
  2850.  
  2851. @@int310500radjustusedf1:
  2852.         sub eax,10h                     ; adjust by size of MCB
  2853.         and eax,0fffffc00h              ; align on K
  2854.         sub eax,cs:rawextmemtop         ; size of extended memory used
  2855.         neg eax
  2856.         shr eax,10                      ; convert from bytes to K
  2857.  
  2858.         mov ebp,cs:codebase             ; EBP = offset of PMODE_TEXT from 0
  2859.         mov ds:rawextmemused[ebp],ax    ; adjust INT 15h extended memory used
  2860.  
  2861. @@int310500radjustuseddone:
  2862.         ret                             ; return
  2863.  
  2864. ;-----------------------------------------------------------------------------
  2865. int310500rlinkmcb:                      ; link memory blocks at ESI and EDI
  2866.         mov eax,[esi-16]                ; combine two block sizes
  2867.         add eax,10h
  2868.         add [edi-16],eax                ; add size of next block to this one
  2869.         mov ecx,[esi-12]                ; copy next MCB field
  2870.         mov [edi-12],ecx
  2871.         jecxz short @@int310500rlinkmcbf0       ; if no next MCB, done
  2872.  
  2873.         mov [ecx-8],edi                 ; set prev MCB in next MCB to this MCB
  2874.  
  2875. @@int310500rlinkmcbf0:
  2876.         ret                             ; return
  2877.  
  2878. ;─────────────────────────────────────────────────────────────────────────────
  2879. int310500r:                             ; raw get free memory information
  2880.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2881.  
  2882.         xor eax,eax                     ; running highest free memory block
  2883. @@int310500rl0:
  2884.         cmp byte ptr [edi-4],0          ; is block free?
  2885.         jne short @@int310500rl0f0      ; if no, loop
  2886.  
  2887.         mov ebx,[edi-16]                ; EBX = size of block
  2888.         cmp eax,ebx                     ; last free block larger?
  2889.         ja short @@int310500rl0f0       ; if yes, loop
  2890.  
  2891.         mov eax,ebx                     ; found larger block, new largest
  2892.  
  2893. @@int310500rl0f0:
  2894.         mov edi,[edi-12]                ; EDI -> next memory control block
  2895.         or edi,edi                      ; is there another MCB?
  2896.         jnz @@int310500rl0              ; if yes, loop
  2897.  
  2898.         jmp int310500xsetbuf            ; put memory information in buffer
  2899.  
  2900. ;─────────────────────────────────────────────────────────────────────────────
  2901. int310501r:                             ; raw allocate memory block
  2902.         call int310500rbxcxtoebx        ; convert BX:CX bytes to EBX bytes
  2903.  
  2904.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2905.  
  2906. @@int310501rl0:
  2907.         cmp byte ptr ds:[edi-4],0       ; is block free?
  2908.         je short @@int310501rl0f2       ; if yes, check block
  2909.  
  2910. @@int310501rl0f0:
  2911.         mov edi,[edi-12]                ; EDI -> next memory control block
  2912.         or edi,edi                      ; is there another MCB?
  2913.         jnz @@int310501rl0              ; if yes, loop
  2914.  
  2915.         jmp int31fail8013               ; fail, error 8013h
  2916.  
  2917. @@int310501rl0f2:
  2918.         lea ecx,[edi-10h]               ; ECX -> possible new MCB
  2919.         sub ecx,ebx
  2920.  
  2921.         mov eax,[edi-16]                ; EAX = size of block
  2922.         sub eax,ebx                     ; enough free memory in block?
  2923.         jc short @@int310501rl0f0       ; if no, loop
  2924.  
  2925.         jz short @@int310501rl0f1       ; if exactly same size, continue
  2926.  
  2927.         sub eax,10h                     ; adjust for size of new created MCB
  2928.         mov [ecx-16],eax                ; put size of new block in new MCB
  2929.         mov eax,ecx                     ; set next MCB in old MCB as new one
  2930.         xchg [edi-12],eax               ; copy next MCB from old to new MCB
  2931.         mov [ecx-12],eax
  2932.         or eax,eax                      ; is there a next MCB?
  2933.         jz short @@int310501rl0f3       ; if no, go on
  2934.  
  2935.         mov [eax-8],ecx                 ; set prev MCB in next MCB to new MCB
  2936.  
  2937. @@int310501rl0f3:
  2938.         mov [ecx-8],edi                 ; set prev MCB in new MCB as old one
  2939.         mov byte ptr [ecx-4],0          ; set new MCB as free
  2940.         mov [edi-16],ebx                ; set size of allocated block
  2941.  
  2942. @@int310501rl0f1:
  2943.         mov byte ptr [edi-4],1          ; set block as allocated
  2944.  
  2945. int310501raddxnhandle:
  2946.         shld ebx,ecx,16                 ; BX:CX = ECX, address of block
  2947.         shld esi,edi,16                 ; SI:DI = EDI, handle (address of MCB)
  2948.  
  2949.         call int310500radjustused       ; adjust INT 15h extended memory used
  2950.  
  2951.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2952.  
  2953. ;─────────────────────────────────────────────────────────────────────────────
  2954. int310502r:                             ; raw free memory block
  2955.         call int310500rfindmcb          ; find MCB for handle SI:DI
  2956.  
  2957.         mov byte ptr [edi-4],0          ; set this memory block as free
  2958.  
  2959.         mov esi,[edi-12]                ; ESI -> next memory control block
  2960.         or esi,esi                      ; is there next MCB?
  2961.         jz short @@int310502rf0         ; if no, go on
  2962.  
  2963.         cmp byte ptr [esi-4],0          ; is next memory block free?
  2964.         jne short @@int310502rf0        ; if no, go on
  2965.  
  2966.         call int310500rlinkmcb          ; link two memory blocks
  2967.  
  2968. @@int310502rf0:
  2969.         mov esi,[edi-8]                 ; ESI -> previous memory control block
  2970.         or esi,esi                      ; is there previous MCB?
  2971.         jz short @@int310502rf1         ; if no, go on
  2972.  
  2973.         cmp byte ptr [esi-4],0          ; is previous memory block free?
  2974.         jne short @@int310502rf1        ; if no, go on
  2975.  
  2976.         xchg esi,edi                    ; change mcb order for function
  2977.         call int310500rlinkmcb          ; link two memory blocks
  2978.  
  2979. @@int310502rf1:
  2980.         call int310500radjustused       ; adjust INT 15h extended memory used
  2981.  
  2982.         jmp int31ok                     ; return ok
  2983.  
  2984. ;─────────────────────────────────────────────────────────────────────────────
  2985. int310503r:                             ; raw resize memory block
  2986.         call int310500rbxcxtoebx        ; convert BX:CX bytes to EBX bytes
  2987.         mov edx,ebx                     ; EDX = size of new block
  2988.  
  2989.         call int310500rfindmcb          ; find MCB for handle SI:DI
  2990.  
  2991.         push ds                         ; ES = DS for possible block copy
  2992.         pop es
  2993.  
  2994.         sub ebx,[esi-16]                ; EBX = change in block size
  2995.         jz @@int310503rf0               ; if no change, done
  2996.  
  2997.         jc @@int310503rf1               ; if block made smaller, just free top
  2998.  
  2999.         xor eax,eax                     ; running memory counter
  3000.  
  3001.         mov ecx,[esi-12]                ; ECX -> next MCB
  3002.         jecxz short @@int310503rf4      ; if no next MCB, check previous MCB
  3003.  
  3004.         cmp byte ptr [ecx-4],0          ; next MCB free?
  3005.         jne short @@int310503rf4        ; if not, check previous MCB
  3006.  
  3007.         mov eax,[ecx-16]                ; EAX = amount of free memory in block
  3008.         add eax,10h                     ;  including memory control block
  3009.  
  3010. @@int310503rf4:
  3011.         mov ecx,[esi-8]                 ; ECX -> previous MCB
  3012.         jecxz short @@int310503rf5      ; if no previous MCB, check memory
  3013.  
  3014.         cmp byte ptr [ecx-4],0          ; previous MCB free?
  3015.         jne short @@int310503rf5        ; if not, check memory
  3016.  
  3017.         add eax,[ecx-16]                ; add amount of free memory in block
  3018.         add eax,10h                     ;  including memory control block
  3019.  
  3020. @@int310503rf5:
  3021.         cmp eax,ebx                     ; enough to resize within area
  3022.         jb @@int310503rf3               ; if no, try to allocate
  3023.  
  3024.         or ecx,ecx                      ; is there a previous MCB?
  3025.         jz @@int310503rf6               ; if no, resize to next
  3026.  
  3027.         cmp byte ptr [ecx-4],0          ; previous MCB free?
  3028.         jne short @@int310503rf6        ; if not, resize to next
  3029.  
  3030.         mov ebp,[ecx-16]                ; EBP = size of previous block, try to
  3031.         add ebp,10h                     ;  resize within previous block
  3032.  
  3033.         sub ebp,ebx                     ; EBP = prev block size - needed size
  3034.         jbe short @@int310503rf7        ; if prev block too small, go on
  3035.  
  3036.         mov edi,ecx                     ; EDI -> new MCB for new memory block
  3037.         sub edi,ebp                     ;  resize will fit entirely
  3038.  
  3039.         lea eax,[ebp-10h]               ; EAX = new size of free block
  3040.         mov [ecx-16],eax                ; store mew free size in prev MCB
  3041.         mov [edi-16],edx                ; store new size in new MCB
  3042.         mov [ecx-12],edi                ; set next MCB in prev MCB to new MCB
  3043.         mov [edi-8],ecx                 ; set prev MCB in new MCB to prev MCB
  3044.         mov byte ptr [edi-4],1          ; set new MCB as used
  3045.  
  3046.         mov ecx,[esi-12]                ; copy next MCB field
  3047.         mov [edi-12],ecx
  3048.         or ecx,ecx                      ; is there a next MCB
  3049.         jz @@int310503rf0               ; if no, go to block readjust
  3050.  
  3051.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3052.  
  3053.         jmp @@int310503rf0              ; go to block readjust
  3054.  
  3055. @@int310503rf7:
  3056.         mov edi,ecx                     ; EDI -> new MCB for new memory block
  3057.  
  3058.         lea eax,[edx+ebp]               ; EAX = size of new block
  3059.         mov [edi-16],eax                ; store mew free size in new MCB
  3060.         mov byte ptr [edi-4],1          ; set new MCB as used
  3061.  
  3062.         mov ecx,[esi-12]                ; copy next MCB field
  3063.         mov [edi-12],ecx
  3064.         jecxz short @@int310503rf8      ; if no next MCB, go on
  3065.  
  3066.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3067.  
  3068. @@int310503rf8:
  3069.         add ebp,ebx                     ; EBP = size of block just acquired
  3070.         sub ebx,ebp                     ; EBX = new size still needed
  3071.         jz @@int310503rf0               ; if no more space needed, done
  3072.  
  3073.         mov esi,edi                     ; ESI -> new MCB
  3074.  
  3075. @@int310503rf6:
  3076.         mov edi,[esi-12]                ; EDI -> next MCB
  3077.  
  3078.         mov ecx,[edi-12]                ; copy next MCB field
  3079.         mov [esi-12],ecx
  3080.         jecxz short @@int310503rf9      ; if no next MCB, go on
  3081.  
  3082.         mov [ecx-8],esi                 ; set prev MCB in next MCB to this MCB
  3083.  
  3084. @@int310503rf9:
  3085.         mov eax,[edi-16]                ; EAX = size of next memory block
  3086.         add eax,10h
  3087.  
  3088.         sub edi,eax                     ; EDI -> start of next memory block
  3089.         sub eax,ebx                     ; EAX = amount of free space left
  3090.  
  3091.         mov ecx,[esi-16]                ; ECX = old size of this memory block
  3092.         mov [esi-16],edx                ; store new size in this MCB
  3093.         mov byte ptr [esi-4],1          ; set this MCB as used
  3094.  
  3095.         sub esi,ecx                     ; ESI -> start of this memory block
  3096.         sub esi,10h
  3097.  
  3098.         shr ecx,2                       ; copy this memory block down in mem
  3099.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  3100.  
  3101.         add esi,10h                     ; adjust ESI to top MCB
  3102.         mov edi,esi                     ; EDI -> top MCB
  3103.  
  3104.         mov ebx,eax                     ; EBX = negative of space free at top
  3105.         neg ebx
  3106.         jz @@int310503rf0               ; in no space free, go to done
  3107.  
  3108.         jmp short @@int310503rf1        ; set new MCBs for moved block
  3109.  
  3110. @@int310503rf3:
  3111.         mov ebp,edi                     ; preserve old block MCB address
  3112.         sub edx,ebx                     ; EDX = size of old block
  3113.  
  3114.         mov bx,[esp+16]                 ; BX:CX = new block size from stack
  3115.         mov cx,[esp+24]
  3116.         mov ax,501h                     ; try to allocate new block
  3117.         int 31h
  3118.         jc int31failax                  ; if could not, fail with error AX
  3119.  
  3120.         shrd eax,esi,16                 ; EAX -> new block MCB
  3121.         mov ax,di
  3122.  
  3123.         shrd edi,ebx,16                 ; EDI -> start of new block
  3124.         mov di,cx
  3125.  
  3126.         lea esi,[ebp-10h]               ; ESI -> start of old block
  3127.         sub esi,edx
  3128.  
  3129.         mov ecx,edx                     ; copy memory from old block to new
  3130.         shr ecx,2
  3131.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  3132.  
  3133.         mov edx,eax                     ; EDX -> new block MCB
  3134.  
  3135.         shld esi,ebp,16                 ; SI:DI = handle of old block
  3136.         mov di,bp
  3137.         mov ax,0502h                    ; free old block
  3138.         int 31h
  3139.  
  3140.         mov edi,edx                     ; EDI -> new block MCB for done
  3141.  
  3142.         jmp short @@int310503rf0        ; go to done
  3143.  
  3144. @@int310503rf1:
  3145.         lea edi,[esi+ebx]               ; EDI -> new MCB for new memory block
  3146.  
  3147.         lea eax,[ebx+10h]               ; EAX = size of freed block
  3148.         neg eax
  3149.         mov [esi-16],eax                ; store freed size in old MCB
  3150.         mov [edi-16],edx                ; store new size in new MCB
  3151.  
  3152.         mov ecx,[esi-12]                ; copy next MCB field
  3153.         mov [edi-12],ecx
  3154.         jecxz short @@int310503rf2      ; if no next MCB, go on
  3155.  
  3156.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3157.  
  3158. @@int310503rf2:
  3159.         mov [esi-12],edi                ; set next MCB in old MCB as new MCB
  3160.         mov [edi-8],esi                 ; set prev MCB in new MCB as old MCB
  3161.         mov byte ptr [edi-4],1          ; set new MCB as used
  3162.         mov byte ptr [esi-4],0          ; set old MCB as free
  3163.  
  3164.         mov ecx,[esi-8]                 ; ECX -> prev MCB of old MCB
  3165.         jecxz short @@int310503rf0      ; if no prev MCB, done
  3166.  
  3167.         cmp byte ptr [ecx-4],0          ; is previous MCB free?
  3168.         jne short @@int310503rf0        ; if no, dont link
  3169.  
  3170.         push edi                        ; preserve new MCB
  3171.         mov edi,ecx                     ; top MCB = prev MCB for link function
  3172.         call int310500rlinkmcb          ; link two memory blocks
  3173.         pop edi                         ; restore new MCB
  3174.  
  3175. @@int310503rf0:
  3176.         mov ecx,[edi-16]                ; ECX = base address of new block
  3177.         neg ecx
  3178.         lea ecx,[ecx+edi-10h]
  3179.         
  3180.         jmp int310501raddxnhandle       ; return address and handle
  3181.  
  3182. ;─────────────────────────────────────────────────────────────────────────────
  3183. int31050ar:                             ; raw get memory block size and base
  3184.         call int310500rfindmcb          ; find MCB for handle SI:DI
  3185.  
  3186.         mov edi,[esi-16]                ; EDI = size of memory block
  3187.         lea ecx,[esi-10h]               ; get base address of memory block
  3188.         sub ecx,edi
  3189.  
  3190.         shld ebx,ecx,16                 ; BX:CX = ECX, address of block
  3191.         shld esi,edi,16                 ; SI:DI = EDI, size of memory block
  3192.  
  3193.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  3194.  
  3195. PMODE_TEXT      ends
  3196. end
  3197.  
  3198.